OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
ValuesElement.cc
Go to the documentation of this file.
1 // This file is part of the "NcML Module" project, a BES module designed
3 // to allow NcML files to be used to be used as a wrapper to add
4 // AIS to existing datasets of any format.
5 //
6 // Copyright (c) 2009 OPeNDAP, Inc.
7 // Author: Michael Johnson <m.johnson@opendap.org>
8 //
9 // For more information, please also see the main website: http://opendap.org/
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // Please see the files COPYING and COPYRIGHT for more information on the GLPL.
26 //
27 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
29 
30 #include "ValuesElement.h"
31 
32 #include "BaseType.h"
33 #include "Array.h"
34 #include "Byte.h"
35 #include "Float32.h"
36 #include "Float64.h"
37 #include "Grid.h"
38 #include "Int16.h"
39 #include "Int32.h"
40 #include "Sequence.h"
41 #include "Str.h"
42 #include "Structure.h"
43 #include "UInt16.h"
44 #include "UInt32.h"
45 #include "Url.h"
46 
47 #include "NCMLDebug.h"
48 #include "NCMLParser.h"
49 #include "NCMLUtil.h"
50 #include <sstream>
51 #include "VariableElement.h"
52 
53 using namespace libdap;
54 
55 namespace ncml_module
56 {
57  const string ValuesElement::_sTypeName = "values";
58  const vector<string> ValuesElement::_sValidAttributes = getValidAttributes();
59 
60  ValuesElement::ValuesElement()
61  : RCObjectInterface()
62  , NCMLElement(0)
63  , _start("")
64  , _increment("")
65  , _separator("")
66  , _gotContent(false)
67  , _tokens()
68  {
69  _tokens.reserve(256);
70  }
71 
73  : RCObjectInterface()
74  , NCMLElement(proto)
75  {
76  _start = proto._start;
77  _increment = proto._increment;
78  _separator = proto._separator;
79  _gotContent = proto._gotContent;
80  _tokens = proto._tokens;
81  }
82 
84  {
85  _tokens.resize(0);
86  }
87 
88  const string&
90  {
91  return _sTypeName;
92  }
93 
96  {
97  return new ValuesElement(*this);
98  }
99 
100  void
102  {
104 
105  _start = attrs.getValueForLocalNameOrDefault("start");
106  _increment = attrs.getValueForLocalNameOrDefault("increment");
107  _separator = attrs.getValueForLocalNameOrDefault("separator", ""); // empty means "not specified" and becoems whitesoace for all but string
108 
109  // Validate them... if _start is specified, then _increment must be as well!
110  if (!_start.empty() && _increment.empty())
111  {
113  "values element=" + toString() +
114  " had a start attribute without a corresponding increment attribute!");
115  }
116  if (_start.empty() && !_increment.empty())
117  {
119  "values element=" + toString() + " had an increment attribute without a corresponding start attribute!");
120  }
121  }
122 
123  void
125  {
127  NCMLParser& p = *_parser;
128 
129  BESDEBUG("ncml", "ValuesElement::handleBegin called with element=" << toString() <<
130  " at scope=" << p.getScopeString() << endl);
131 
132  // First, make sure we're in a current parse start for this elemnent
133  if (!p.isScopeVariable())
134  {
136  "Got values element while not parsing a variable! values=" + toString() +
137  " at scope=" + p.getTypedScopeString());
138  }
139 
140  // Make sure we're the first values element on the variable or there is a problem!
141  const VariableElement* pVarElt = getContainingVariableElement(p);
142  VALID_PTR(pVarElt);
143  if (pVarElt->checkGotValues())
144  {
146  "Got a values element when one was already specified for this variable=" +
147  pVarElt->toString() +
148  " at scope=" + p.getScopeString());
149  }
150 
151  // If we got a start and increment, we are supposed to auto-generate values for the variable
152  if (shouldAutoGenerateValues())
153  {
154  BaseType* pVar = p.getCurrentVariable();
155  NCML_ASSERT_MSG(pVar, "ValuesElement::handleBegin(): Expected non-null p.getCurrentVariable()!");
156  autogenerateAndSetVariableValues(p, *pVar);
157  }
158  // else we'll expect content
159 
160  // We zero this out here in 'begin'; load it up with raw text in 'handlerContent'
161  // and parse it in 'end'. jhrg 10/12/11
162  _accumulated_content.resize(0);
163  }
164 
165  void
166  ValuesElement::handleContent(const string& content)
167  {
168  NCMLParser& p = *_parser;
169 
170  BESDEBUG("ncml", "ValuesElement::handleContent called for " << toString() << " with content=" << content << endl);
171 
172  // N.B. Technically, we're still in isScopeVariable() since we don't push values elements on the scopestack,
173  // only the XML parser stack...
174 
175  // Make sure we don't get non-whitespace content for autogenerated values!
176  if (shouldAutoGenerateValues() && !NCMLUtil::isAllWhitespace(content))
177  {
179  "Element: " + toString() +
180  " specified a start and increment to autogenerate values but also illegally specified content!");
181  }
182 
183  // There had better be one or we goofed!
184  BaseType* pVar = p.getCurrentVariable();
185  NCML_ASSERT_MSG(pVar, "ValuesElement::handleContent: got unexpected null getCurrentVariable() from parser!!");
186 
187  // Also, make sure the variable we plan to add values to is a new variable and not an existing one.
188  // We do not support changing existing dataset values currently.
189  const VariableElement* pVarElt = getContainingVariableElement(p);
190  VALID_PTR(pVarElt);
191  if (!pVarElt->isNewVariable())
192  {
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());
196  }
197 
198  // Ripped out this block; moved to 'handleEnd'. Just accumulate raw text here. jhrg 10/12/11
199  _accumulated_content.append(content);
200 
201 #if 0
202  // Tokenize the values for all cases EXCEPT if it's a scalar string.
203  // We'll make a special exception an assume the entire content is the token
204  // to avoid accidental tokenization with whitespace, which is clearly not intended
205  // by the NcML file author!
206  if (pVar->is_simple_type() &&
207  (pVar->type() == dods_str_c || pVar->type() == dods_url_c))
208  {
209  _tokens.resize(0);
210  _tokens.push_back(string(content));
211  }
212  // Don't tokenize a char array either, since we want to read all the char's in.
213  else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) == "char")
214  {
215  NCMLUtil::tokenizeChars(content, _tokens); // tokenize with no separator so each char is token.
216  }
217  else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) == "string")
218  {
219  string sep = ((_separator.empty())?(NCMLUtil::WHITESPACE):(_separator));
220  NCMLUtil::tokenize(content, _tokens, sep);
221  }
222  else // for arrays of other values, use whitespace separation for default if not specified.
223  {
224  string sep = ((_separator.empty())?(NCMLUtil::WHITESPACE):(_separator));
225  NCMLUtil::tokenize(content, _tokens, sep);
226  }
227 #endif
228 #if 0
229  setVariableValuesFromTokens(p, *pVar);
230  _gotContent = true;
231  setGotValuesOnOurVariableElement(p);
232 #endif
233  }
234 
235  void
237  {
238  BESDEBUG("ncml", "ValuesElement::handleEnd called for " << toString() << endl);
239 
240  NCMLParser& p = *_parser;
241  // There had better be one or we goofed!
242  BaseType* pVar = p.getCurrentVariable();
243  NCML_ASSERT_MSG(pVar, "ValuesElement::handleContent: got unexpected null getCurrentVariable() from parser!!");
244 
245  // I set _gotContent here because other methods depend on it.
246  _gotContent = !_accumulated_content.empty();
247 #if 0
248  if (!shouldAutoGenerateValues() && !_gotContent)
249  {
251  "Values element=" + toString() + " expected content for values but didn't get any!");
252  }
253 #endif
254  // Tokenize the values for all cases EXCEPT if it's a scalar string.
255  // We'll make a special exception an assume the entire content is the token
256  // to avoid accidental tokenization with whitespace, which is clearly not intended
257  // by the NcML file author!
258  if (pVar->is_simple_type() && (pVar->type() == dods_str_c || pVar->type() == dods_url_c))
259  {
260  _tokens.resize(0);
261  _tokens.push_back(string(_accumulated_content));
262  }
263  // Don't tokenize a char array either, since we want to read all the char's in.
264  else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) == "char")
265  {
266  NCMLUtil::tokenizeChars(_accumulated_content, _tokens); // tokenize with no separator so each char is token.
267  }
268  else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) == "string")
269  {
270  string sep = ((_separator.empty())?(NCMLUtil::WHITESPACE):(_separator));
271  NCMLUtil::tokenize(_accumulated_content, _tokens, sep);
272  }
273  else // for arrays of other values, use whitespace separation for default if not specified.
274  {
275  string sep = ((_separator.empty())?(NCMLUtil::WHITESPACE):(_separator));
276  NCMLUtil::tokenize(_accumulated_content, _tokens, sep);
277  }
278 
279  if (!shouldAutoGenerateValues())
280  {
281  setVariableValuesFromTokens(p, *pVar);
282  setGotValuesOnOurVariableElement(p);
283  }
284 
285  // In the original version of this method, the 'if' before this was
286  // if (!shouldAutoGenerateValues() && !_gotContent) and it throws/threw an
287  // exception (I moved that code up in my modification of this method). But
288  // dealWithEmptyStringValues() only does something when _gotContent is false,
289  // so there's no way to get to call dealWithEmptyStringValues here. I'm
290  // removing it and looking at the tests. jhrg 10/12/11
291 #if 0
292  // if unspecified, string and url vars get set to empty string ""
293  if (!shouldAutoGenerateValues())
294  {
295  dealWithEmptyStringValues();
296  }
297  // Otherwise, we're all good.
298 #endif
299  }
300 
301  string
303  {
304  return "<" +_sTypeName + " " +
305  ((_start.empty())?(""):("start=\"" + _start + "\" ")) +
306  ((_increment.empty())?(""):("increment=\"" + _increment + "\" ")) +
307  ((_separator == NCMLUtil::WHITESPACE)?(""):("separator=\"" + _separator + "\" ")) +
308  ">";
309  }
310 
311  void
312  ValuesElement::validateStartAndIncrementForVariableTypeOrThrow(libdap::BaseType& /* pVar */) const
313  {
314  // TODO IMPL ME
315  // Look up the types...
316  }
317 
318  template <class DAPType, typename ValueType>
319  void
320  ValuesElement::setScalarValue(libdap::BaseType& var, const string& valueAsToken)
321  {
322  // Make sure we got the right subclass type
323  DAPType* pVar = dynamic_cast<DAPType*>(&var);
324  NCML_ASSERT_MSG(pVar, "setScalarValue() got called with BaseType not matching the expected type.");
325 
326  // Parse the token using stringstream and the template ValueType.
327  std::stringstream sis;
328  sis.str(valueAsToken);
329  ValueType value;
330  sis >> value;
331  if (sis.fail())
332  {
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);
336  }
337 
338  // assuming it works, there should be a setValue(ValueType) on pVar now
339  pVar->set_value(value);
340  }
341 
346  template <>
347  void
348  ValuesElement::setScalarValue<Byte, dods_byte>(libdap::BaseType& var, const string& valueAsToken)
349  {
350  Byte* pVar = dynamic_cast<Byte*>(&var);
351  NCML_ASSERT_MSG(pVar, "setScalarValue() got called with BaseType not matching the expected type.");
352 
353  std::stringstream sis;
354  sis.str(valueAsToken);
355  dods_uint16 value; // read it as an unsigned short.
356  sis >> value;
357  if (sis.fail())
358  {
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);
363  }
364 
365  // then cast it for the set...
366  pVar->set_value(static_cast<dods_byte>(value));
367  }
368 
372  template <>
373  void
374  ValuesElement::setScalarValue<Str, string>(libdap::BaseType& var, const string& valueAsToken)
375  {
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);
379  }
380 
381 
385  template <>
386  void
387  ValuesElement::setScalarValue<Url, string>(libdap::BaseType& var, const string& valueAsToken)
388  {
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);
392  }
393 
394  template <typename DAPType>
395  void
396  ValuesElement::setVectorValues(libdap::Array* pArray, const vector<string>& valueTokens)
397  {
398  VALID_PTR(pArray);
399  // Make an array of values ready to read them all the tokens.
400  vector<DAPType> values;
401  values.reserve(valueTokens.size());
402 
403  int count=0; // only to help error output msg
404  vector<string>::const_iterator endIt = valueTokens.end();
405  for (vector<string>::const_iterator it = valueTokens.begin(); it != endIt; ++it)
406  {
407  DAPType value;
408  stringstream valueTokenAsStream;
409  const std::string& token = *it;
410  valueTokenAsStream.str(token);
411  valueTokenAsStream >> value;
412  if (valueTokenAsStream.fail())
413  {
414  stringstream msg;
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) <<
418  " for element " << toString();
420  }
421  values.push_back(value);
422  count++;
423  }
424 
425  // Call the overloaded set with the parsed vector.
426  pArray->set_value(values, values.size());
427  }
428 
432  template<>
433  void
434  ValuesElement::setVectorValues <string> (libdap::Array* pArray, const vector<string>& valueTokens)
435  {
436  VALID_PTR(pArray);
437  // Call it DIRECTLY with the given values, modulo const_cast
438  vector<string>& values = const_cast< vector<string>& >(valueTokens);
439  pArray->set_value(values, values.size());
440  }
441 
445  void
446  ValuesElement::parseAndSetCharValue(libdap::BaseType& var, const string& valueAsToken)
447  {
448  Byte* pVar = dynamic_cast<Byte*>(&var);
449  NCML_ASSERT_MSG(pVar, "setScalarValue() got called with BaseType not matching the expected type.");
450 
451  if (valueAsToken.size() != 1)
452  {
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);
456  }
457 
458  // Read the char and set it
459  dods_byte val = valueAsToken.at(0);
460  pVar->set_value(val);
461  }
462 
463  void
464  ValuesElement::parseAndSetCharValueArray(NCMLParser& /* p */, libdap::Array* pVecVar, const vector<string>& tokens)
465  {
466  vector<dods_byte> values;
467  for (unsigned int i=0; i<tokens.size(); ++i)
468  {
469  values.push_back(static_cast<dods_byte>((tokens.at(i))[0]));
470  }
471  pVecVar->set_value(values, values.size());
472  }
473 
474  void
475  ValuesElement::setVariableValuesFromTokens(NCMLParser& p, libdap::BaseType& var)
476  {
477  // It's an error to have <values> for a Structure variable!
478  if (var.type() == dods_structure_c)
479  {
481  "Illegal to specify <values> element for a Structure type variable name=" + var.name() +
482  " at scope=" + p.getScopeString());
483  }
484  // First, make sure the dimensionality matches or we're doomed from the get-go
485  if (var.is_simple_type())
486  {
487  setScalarVariableValuesFromTokens(p, var);
488  }
489  else if (var.is_vector_type())
490  {
491  setVectorVariableValuesFromTokens(p, var);
492  }
493  else
494  {
496  "Can't call ValuesElement::setVariableValuesFromTokens for constructor type now!! "
497  "Variable named " + var.name() + " at scope=" + p.getScopeString());
498  }
499  }
500 
501  void
502  ValuesElement::setScalarVariableValuesFromTokens(NCMLParser& p, libdap::BaseType& var)
503  {
504  // OK, we have a scalar, so make sure there's exactly one token!
505  if (_tokens.size() != 1)
506  {
507  stringstream msg;
508  msg << "While setting scalar variable name=" << var.name() <<
509  " we expected exactly 1 value in content but found " << _tokens.size() <<
510  " tokens.";
512  msg.str());
513  }
514 
515  // OK, we have one token for a scalar. Now make sure it's a valid value for the given type.
516  // legacy "char" type (internally a byte) is specified differently, so don't check for that case.
517  if (getNCMLTypeForVariable(p) != "char")
518  {
519  p.checkDataIsValidForCanonicalTypeOrThrow(var.type_name(), _tokens);
520  }
521 
522  // Just one of em
523  const string& valueToken = _tokens.at(0);
524 
525  // OK, now it gets pretty ugly, but we hid most of it behind a template...
526  Type varType = var.type();
527  switch (varType)
528  {
529  case dods_byte_c:
530  // Special case depending on whether the underlying NcML was type-converted
531  // from "char" or not. If char, we parse as char, not numeric
532  if (getNCMLTypeForVariable(p) == "char")
533  {
534  parseAndSetCharValue(var, valueToken);
535  }
536  else
537  {
538  setScalarValue <Byte, dods_byte> (var, valueToken);
539  }
540  break;
541 
542  case dods_int16_c:
543  setScalarValue<Int16, dods_int16>(var, valueToken);
544  break;
545 
546  case dods_uint16_c:
547  setScalarValue<UInt16, dods_uint16>(var, valueToken);
548  break;
549 
550  case dods_int32_c:
551  setScalarValue<Int32, dods_int32>(var, valueToken);
552  break;
553 
554  case dods_uint32_c:
555  setScalarValue<UInt32, dods_uint32>(var, valueToken);
556  break;
557 
558  case dods_float32_c:
559  setScalarValue<Float32, dods_float32>(var, valueToken);
560  break;
561 
562  case dods_float64_c:
563  setScalarValue<Float64, dods_float64>(var, valueToken);
564  break;
565 
566  case dods_str_c:
567  setScalarValue<Str, string>(var, valueToken);
568  break;
569 
570  case dods_url_c:
571  setScalarValue<Url, string>(var, valueToken);
572  break;
573 
574  default:
575  THROW_NCML_INTERNAL_ERROR("Expected simple type but didn't find it!");
576  break;
577  }
578  }
579 
580  void
581  ValuesElement::setVectorVariableValuesFromTokens(NCMLParser& p, libdap::BaseType& var)
582  {
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!!");
586 
587  // Make sure the Array length matches the number of tokens.
588  // Note that length() should be the product of dimension sizes since N-D arrays are flattened in row major order
589  if (pVecVar->length() > 0 &&
590  static_cast<unsigned int>(pVecVar->length()) != _tokens.size())
591  {
592  stringstream msg;
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();
598  }
599 
600  // Make sure all the tokens are valid for the given datatype
601  if (getNCMLTypeForVariable(p) != "char")
602  {
603  BaseType* pTemplate = var.var();
604  VALID_PTR(pTemplate);
605  p.checkDataIsValidForCanonicalTypeOrThrow(pTemplate->type_name(), _tokens);
606  }
607 
608  // Finally, go and parse the values in for the given type and set them in the vector
609  VALID_PTR(pVecVar->var());
610  libdap::Type valType = pVecVar->var()->type();
611  switch (valType)
612  {
613  case dods_byte_c:
614  // Special case depending on whether the underlying NcML was type-converted
615  // from "char" or not. If so, read the ascii character not the numeric version of it.
616  if (getNCMLTypeForVariable(p) == "char")
617  {
618  parseAndSetCharValueArray(p, pVecVar, _tokens);
619  }
620  else
621  {
622  setVectorValues <dods_byte> (pVecVar, _tokens);
623  }
624  break;
625 
626  case dods_int16_c:
627  setVectorValues <dods_int16> (pVecVar, _tokens);
628  break;
629 
630  case dods_uint16_c:
631  setVectorValues <dods_uint16> (pVecVar, _tokens);
632  break;
633 
634  case dods_int32_c:
635  setVectorValues <dods_int32> (pVecVar, _tokens);
636  break;
637 
638  case dods_uint32_c:
639  setVectorValues <dods_uint32> (pVecVar, _tokens);
640  break;
641 
642  case dods_float32_c:
643  setVectorValues <dods_float32> (pVecVar, _tokens);
644  break;
645 
646  case dods_float64_c:
647  setVectorValues <dods_float64> (pVecVar, _tokens);
648  break;
649 
650  case dods_str_c:
651  setVectorValues <string> (pVecVar, _tokens);
652  break;
653 
654  case dods_url_c:
655  setVectorValues <string> (pVecVar, _tokens);
656  break;
657 
658  default:
659  THROW_NCML_INTERNAL_ERROR("Expected Vector template type was a simple type but didn't find it!");
660  break;
661  } // switch
662 
663  }
664 
665  template <typename DAPType>
666  void
667  ValuesElement::generateAndSetVectorValues(NCMLParser& p, libdap::Array* pArray)
668  {
669  // 1) Check that the start and increment values can be parsed into the appropriate type
670  // 2) Find out the dimensionality
671  // 3) Generate a vector of values with the dimensionality
672  // 4) Set it on pArray
673 
674  DAPType start;
675  {
676  stringstream sis;
677  sis.str(_start);
678  sis >> start;
679  if (sis.fail())
680  {
682  "Failed to parse the values@start=" + _start + " for " + toString() +
683  " at scope=" + p.getScopeString());
684  }
685  }
686 
687  DAPType increment;
688  {
689  stringstream sis;
690  sis.str(_increment);
691  sis >> increment;
692  if (sis.fail())
693  {
695  "Failed to parse the values@increment=" + _start + " for " + toString() +
696  " at scope=" + p.getScopeString());
697  }
698  }
699 
700  int numPoints = pArray->length();
701  NCML_ASSERT(numPoints >= 1);
702  vector<DAPType> values;
703  values.reserve(numPoints);
704  DAPType x = start;
705  values.push_back(x);
706  for (int i=1; i<numPoints; ++i)
707  {
708  x += increment;
709  values.push_back(x);
710  }
711  NCML_ASSERT(values.size() == static_cast<unsigned int>(numPoints));
712  pArray->set_value(values, values.size());
713  }
714 
715  void
716  ValuesElement::autogenerateAndSetVariableValues(NCMLParser& p, BaseType& var)
717  {
718  // First, make sure var is an Array or we don't know what to do
719  libdap::Array* pArray = dynamic_cast<libdap::Array*>(&var);
720  if (!pArray)
721  {
722  THROW_NCML_INTERNAL_ERROR("ValuesElement::autogenerateAndSetVariableValues: expected variable of type libdap::Array but failed to cast it!");
723  }
724 
725  setGotValuesOnOurVariableElement(p);
726 
727  // Next, find out the underlying type and use the class's template calls.
728  libdap::BaseType* pTemplate = pArray->var();
729  VALID_PTR(pTemplate);
730  switch (pTemplate->type())
731  {
732  case dods_byte_c:
733  // This doesn't work for char!
734  if (getNCMLTypeForVariable(p) == "char")
735  {
737  "Can't use values@start for non-numeric values!");
738  }
739  else // it works for bytes
740  {
741  generateAndSetVectorValues <dods_byte> (p, pArray);
742  }
743  break;
744 
745  case dods_int16_c:
746  generateAndSetVectorValues <dods_int16> (p, pArray);
747  break;
748 
749  case dods_uint16_c:
750  generateAndSetVectorValues <dods_uint16> (p, pArray);
751  break;
752 
753  case dods_int32_c:
754  generateAndSetVectorValues <dods_int32> (p, pArray);
755  break;
756 
757  case dods_uint32_c:
758  generateAndSetVectorValues <dods_uint32> (p, pArray);
759  break;
760 
761  case dods_float32_c:
762  generateAndSetVectorValues <dods_float32> (p, pArray);
763  break;
764 
765  case dods_float64_c:
766  generateAndSetVectorValues <dods_float64> (p, pArray);
767  break;
768 
769  // User error
770  case dods_str_c:
771  case dods_url_c:
773  "Can't use values@start for non-numeric values!");
774  break;
775 
776  default:
777  THROW_NCML_INTERNAL_ERROR("Expected Vector template type was a simple type but didn't find it!");
778  break;
779  } // switch
780 
781  }
782 
783  std::string
784  ValuesElement::getNCMLTypeForVariable(NCMLParser& p) const
785  {
786  const VariableElement* pMyParent = getContainingVariableElement(p);
787  VALID_PTR(pMyParent);
788  return pMyParent->type();
789  }
790 
791  const VariableElement*
792  ValuesElement::getContainingVariableElement(NCMLParser& p) const
793  {
794  const VariableElement* ret = 0;
795 
796  // Get the parse stack for p and walk up it!
797  NCMLParser::ElementStackConstIterator it;
798  NCMLParser::ElementStackConstIterator endIt = p.getElementStackEnd();
799  for (it = p.getElementStackBegin(); it != endIt; ++it)
800  {
801  const NCMLElement* pElt = *it;
802  const VariableElement* pVarElt = dynamic_cast<const VariableElement*>(pElt);
803  if (pVarElt)
804  {
805  ret = pVarElt;
806  break;
807  }
808  }
809  return ret;
810  }
811 
812  void
813  ValuesElement::setGotValuesOnOurVariableElement(NCMLParser& p)
814  {
815  // Ugh, I know I shouldn't do this, but...
816  VariableElement* pContainingVar = const_cast<VariableElement*>(getContainingVariableElement(p));
817  VALID_PTR(pContainingVar);
818  pContainingVar->setGotValues();
819  }
820 
821  // I'm not sure I understand this method - I think it's use in handleEnd() is
822  // no longer needed given the changes I made there. jhrg 10/12/11
823  void
824  ValuesElement::dealWithEmptyStringValues()
825  {
826  // To reuse all the logic, we'll just explicitly call handleContent("")
827  // which will push an empty string token for scalar string and url.
828  if (!_gotContent)
829  {
830  handleContent("");
831  }
832  }
833 
834  vector<string>
835  ValuesElement::getValidAttributes()
836  {
837  vector<string> validAttrs;
838  validAttrs.reserve(3);
839  validAttrs.push_back("start");
840  validAttrs.push_back("increment");
841  validAttrs.push_back("separator");
842  // we disallow npts since it was deprecated and we'll be used for new files.
843  return validAttrs;
844  }
845 
846 
847 }
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...
Definition: NCMLElement.cc:191
#define NCML_ASSERT(cond)
Definition: NCMLDebug.h:80
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.
Definition: XMLHelpers.cc:209
static bool isAllWhitespace(const std::string &str)
Is all the string whitespace as defined by chars in WHITESPACE ?
Definition: NCMLUtil.cc:110
#define NCML_ASSERT_MSG(cond, msg)
Definition: NCMLDebug.h:83
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.
Definition: NCMLUtil.cc:82
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.
int getParseLineNumber() const
Get the line of the NCML file the parser is currently parsing.
Definition: NCMLParser.cc:222
static const string _sTypeName
Definition: ValuesElement.h:57
#define THROW_NCML_PARSE_ERROR(parseLine, msg)
Definition: NCMLDebug.h:69
NCMLElement(NCMLParser *p)
Definition: NCMLElement.cc:147
Base class for NcML element concrete classes.
Definition: NCMLElement.h:64
virtual string toString() const
Return a string describing the element.
#define THROW_NCML_INTERNAL_ERROR(msg)
Definition: NCMLDebug.h:61
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 VALID_PTR(ptr)
Definition: NCMLDebug.h:88
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
static const std::string WHITESPACE
Delimiter set for tokenizing whitespace separated data.
Definition: NCMLUtil.h:79
static const vector< string > _sValidAttributes
Definition: ValuesElement.h:58
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.
Definition: NCMLUtil.cc:54