33 #include <Structure.h>
34 #include <dods-limits.h>
54 const string VariableElement::_sTypeName =
"variable";
55 const vector<string> VariableElement::_sValidAttributes = getValidAttributes();
57 VariableElement::VariableElement()
65 , _pNewlyCreatedVar(0)
76 _shape = proto._shape;
77 _orgName = proto._orgName;
78 _shapeTokens = proto._shapeTokens;
79 _pNewlyCreatedVar = 0;
86 _shapeTokens.resize(0);
127 "Got non-whitespace for element content and didn't expect it. "
128 "Element=" +
toString() +
" content=\"" +
143 " name=\"" + _name +
"\"" +
144 " type=\"" + _type +
"\"" +
145 ((!_shape.empty())?(
" shape=\"" + _shape +
"\""):(
"")) +
146 ((!_orgName.empty())?(
" orgName=\"" + _orgName +
"\""):(
"")) +
153 return _pNewlyCreatedVar;
174 BESDEBUG(
"ncml",
"VariableElement::handleBegin called for " <<
toString() << endl);
176 if (!p.withinNetcdf())
179 "Got element " +
toString() +
" while not in <netcdf> node!");
183 if (!(p.isScopeGlobal() || p.isScopeCompositeVariable()))
187 "Got <variable> element while not within a <netcdf> or within variable container. scope=" +
192 if (!_orgName.empty())
194 processRenameVariable(p);
200 BaseType* pVar = p.getVariableInCurrentVariableContainer(_name);
203 processNewVariable(p);
207 processExistingVariable(p, pVar);
213 VariableElement::processEnd(NCMLParser& p)
215 BESDEBUG(
"ncml",
"VariableElement::handleEnd called at scope:" << p.getScopeString() << endl);
216 if (!p.isScopeVariable())
220 "VariableElement::handleEnd called when not parsing a variable element! "
221 "Scope=" + p.getTypedScopeString());
237 " the newly created variable=" <<
toString() <<
238 " did not have its values set! We will assume this is a placeholder variable"
239 " for an aggregation (such as the new outer dimension of a joinNew) and will"
240 " defer checking that required values are set until the point when this "
241 " netcdf element is closed..."
242 " Scope=" << p.getScopeString() <<
244 BESDEBUG(
"ncml",
"Adding new variable name=" << _pNewlyCreatedVar->name() <<
245 " to the validation watch list for the closing of this netcdf." << endl);
249 NCML_ASSERT_MSG(p.getCurrentVariable(),
"Error: VariableElement::handleEnd(): Expected non-null parser.getCurrentVariable()!");
254 BaseType* pVar = p.getCurrentVariable();
255 BESDEBUG(
"ncml",
"Variable scope now with name: " << ((pVar)?(pVar->name()):(
"<NULL>")) << endl);
259 VariableElement::processExistingVariable(NCMLParser& p, BaseType* pVar)
261 BESDEBUG(
"ncml",
"VariableElement::processExistingVariable() called with name=" << _name <<
" at scope=" << p.getTypedScopeString() << endl);
266 pVar = p.getVariableInCurrentVariableContainer(_name);
277 if (!_type.empty() && !p.typeCheckDAPVariable(*pVar, p.convertNcmlTypeToCanonicalType(_type)))
281 "Type Mismatch in variable element with name=" + _name +
282 " at scope=" + p.getScopeString() +
283 " Expected type=" + _type +
284 " but found variable with type=" + pVar->type_name() +
285 " To match a variable of any type, please do not specify variable@type.");
293 VariableElement::processRenameVariable(NCMLParser& p)
295 BESDEBUG(
"ncml",
"VariableElement::processRenameVariable() called on " +
toString() <<
" at scope=" << p.getTypedScopeString() << endl);
298 NCML_ASSERT_MSG(!_name.empty(),
"Can't have an empty variable@name if variable@orgName is specified!");
302 BESDEBUG(
"ncml",
"Looking up the existence of a variable with name=" << _orgName <<
"..." <<endl);
303 BaseType* pOrgVar = p.getVariableInCurrentVariableContainer(_orgName);
307 "Renaming variable failed for element=" +
toString() +
308 " since no variable with orgName=" + _orgName +
309 " exists at current parser scope=" + p.getScopeString());
311 BESDEBUG(
"ncml",
"Found variable with name=" << _orgName << endl);
314 BESDEBUG(
"ncml",
"Making sure new name=" << _name <<
" does not exist at this scope already..." << endl);
315 BaseType* pExisting = p.getVariableInCurrentVariableContainer(_name);
319 "Renaming variable failed for element=" +
toString() +
320 " since a variable with name=" + _name +
321 " already exists at current parser scope=" + p.getScopeString());
323 BESDEBUG(
"ncml",
"Success, new variable name is open at this scope." << endl);
326 BESDEBUG(
"ncml",
"Renaming variable " << _orgName <<
" to " << _name << endl);
330 if (p.parsingDataRequest())
333 if (!dynamic_cast<Array*>(pOrgVar))
340 pOrgVar = replaceArrayIfNeeded(p, pOrgVar, _name);
357 auto_ptr<BaseType> pCopy = auto_ptr<BaseType>(pOrgVar->ptr_duplicate());
361 p.deleteVariableAtCurrentScope(pOrgVar->name());
364 p.addCopyOfVariableAtCurrentScope(*pCopy);
368 BaseType* pRenamedVar = p.getVariableInCurrentVariableContainer(_name);
369 NCML_ASSERT_MSG(pRenamedVar,
"Renamed variable not found! Logic error!");
372 enterScope(p, pRenamedVar);
373 BESDEBUG(
"ncml",
"Entering scope of the renamed variable. Scope is now: " << p.getTypedScopeString() << endl);
377 VariableElement::processNewVariable(NCMLParser& p)
379 BESDEBUG(
"ncml",
"Entered VariableElement::processNewVariable..." << endl);
387 "Must have non-empty variable@type when creating new variable=" +
toString());
391 string type = p.convertNcmlTypeToCanonicalType(_type);
395 "Unknown type for new variable=" +
toString());
405 if (_type == p.STRUCTURE_TYPE)
407 processNewStructure(p);
409 else if (_shape.empty())
411 processNewScalar(p, type);
413 else if (!_shape.empty())
415 processNewArray(p, type);
425 _pNewlyCreatedVar =
_parser->getCurrentVariable();
429 VariableElement::processNewStructure(NCMLParser& p)
432 if (!(p.isScopeCompositeVariable() || p.isScopeGlobal()))
435 "Cannot add a new Structure variable at current scope! "
436 "TypedScope=" + p.getTypedScopeString());
440 NCML_ASSERT_MSG(pNewVar.get(),
"VariableElement::processNewStructure: factory failed to make a new Structure variable for name=" + _name);
443 p.addCopyOfVariableAtCurrentScope(*pNewVar);
446 BaseType* pActualVar = p.getVariableInCurrentVariableContainer(_name);
452 enterScope(p, pActualVar);
459 VariableElement::processNewScalar(NCMLParser&p,
const string& dapType)
461 addNewVariableAndEnterScope(p, dapType);
465 VariableElement::processNewArray(NCMLParser& p,
const std::string& dapType)
469 addNewVariableAndEnterScope(p,
"Array<" + dapType +
">");
473 Array* pNewVar =
dynamic_cast<Array*
>(p.getCurrentVariable());
474 NCML_ASSERT_MSG(pNewVar,
"VariableElement::processNewArray: Expected non-null getCurrentVariable() in parser but got NULL!");
478 pNewVar->add_var(pTemplateVar.get());
481 for (
unsigned int i=0; i<_shapeTokens.size(); ++i)
483 unsigned int dim = getSizeForDimension(p, _shapeTokens.at(i));
484 string dimName = ((isDimensionNumericConstant(_shapeTokens.at(i)))?(
""):(_shapeTokens.at(i)));
485 BESDEBUG(
"ncml",
"Appending dimension name=\"" << dimName <<
"\" of size=" << dim <<
" to the Array name=" << pNewVar->name() << endl);
486 pNewVar->append_dim(dim, dimName);
490 if (getProductOfDimensionSizes(p) > static_cast<unsigned int>(DODS_MAX_ARRAY))
493 "Product of dimension sizes for Array must be < (2^31-1).");
497 #if 0 // old school copy method
499 VariableElement::replaceArrayIfNeeded(NCMLParser& p, libdap::BaseType* pOrgVar,
const string& name)
502 Array* pOrgArray =
dynamic_cast<libdap::Array*
>(pOrgVar);
508 BESDEBUG(
"ncml",
"VariableElement::replaceArray if needed. Renaming an Array means we need to convert it to NCMLArray." << endl);
515 p.deleteVariableAtCurrentScope(pOrgArray->name());
522 p.addCopyOfVariableAtCurrentScope(*(pNewArray.get()));
524 return p.getVariableInCurrentVariableContainer(name);
529 VariableElement::replaceArrayIfNeeded(NCMLParser& p, libdap::BaseType* pOrgVar,
const string& name)
532 Array* pOrgArray =
dynamic_cast<libdap::Array*
>(pOrgVar);
538 BESDEBUG(
"ncml",
"VariableElement::replaceArray if needed. Renaming an Array means we need to wrap it with RenamedArrayWrapper!" << endl);
541 auto_ptr<RenamedArrayWrapper> pNewArray =
542 auto_ptr<RenamedArrayWrapper>(
new RenamedArrayWrapper(dynamic_cast<Array*>(pOrgArray->ptr_duplicate())));
543 p.deleteVariableAtCurrentScope(pOrgArray->name());
550 p.addCopyOfVariableAtCurrentScope(*(pNewArray.get()));
552 return p.getVariableInCurrentVariableContainer(name);
556 VariableElement::addNewVariableAndEnterScope(NCMLParser& p,
const std::string& dapType)
559 if (!(p.isScopeCompositeVariable() || p.isScopeGlobal()))
562 "Cannot add a new scalar variable at current scope! TypedScope=" + p.getTypedScopeString());
567 NCML_ASSERT_MSG(pNewVar.get(),
"VariableElement::addNewVariable: factory failed to make a new variable of type: " + dapType +
572 p.addCopyOfVariableAtCurrentScope(*pNewVar);
575 BaseType* pActualVar = p.getVariableInCurrentVariableContainer(_name);
581 enterScope(p, pActualVar);
586 VariableElement::enterScope(NCMLParser& p, BaseType* pVar)
591 if (pVar->is_constructor_type())
601 p.setCurrentVariable(pVar);
605 VariableElement::exitScope(NCMLParser& p)
609 p.setCurrentVariable(p.getCurrentVariable()->get_parent());
615 VariableElement::isDimensionNumericConstant(
const std::string& dimToken)
const
618 return isdigit(dimToken.at(0));
622 VariableElement::getSizeForDimension(NCMLParser& p,
const std::string& dimToken)
const
624 unsigned int dim = 0;
626 if (isDimensionNumericConstant(dimToken))
634 "Trying to get the dimension size in shape=" + _shape +
" for token " + dimToken +
635 " failed to parse the unsigned int!");
640 const DimensionElement* pDim = p.getDimensionAtLexicalScope(dimToken);
643 return pDim->getLengthNumeric();
648 "Failed to find a dimension with name=" + dimToken +
650 " with dimension table= " + p.printAllDimensionsAtLexicalScope() +
651 " at scope=" + p.getScopeString());
658 VariableElement::getProductOfDimensionSizes(NCMLParser& p)
const
667 unsigned int product = 1;
668 vector<string>::const_iterator endIt = _shapeTokens.end();
669 vector<string>::const_iterator it;
670 for (it = _shapeTokens.begin(); it != endIt; ++it)
672 const string& dimName = *it;
673 unsigned int dimSize = getSizeForDimension(p, dimName);
675 if (dimSize > (DODS_MAX_ARRAY/product))
678 "Product of dimension sizes exceeds the maximum DAP2 size of 2147483647 (2^31-1)!");
687 VariableElement::getValidAttributes()
689 vector<string> validAttrs;
690 validAttrs.reserve(4);
691 validAttrs.push_back(
"name");
692 validAttrs.push_back(
"type");
693 validAttrs.push_back(
"shape");
694 validAttrs.push_back(
"orgName");
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...
void addVariableToValidateOnClose(libdap::BaseType *pNewVar, VariableElement *pVE)
Add the pNewvar created by pVE to this dataset's list of variables to validate for having values set ...
virtual void setAttributes(const XMLAttributeMap &attrs)
Set the attributes of this from the map.
const std::string type() const
#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)
virtual void handleBegin()
Handle a begin on this element.
static class NCMLUtil overview
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.
virtual void handleContent(const string &content)
Handle the characters content for the element.
#define THROW_NCML_PARSE_ERROR(parseLine, msg)
virtual ~VariableElement()
static std::auto_ptr< libdap::BaseType > makeVariable(const libdap::Type &type, const string &name)
Return a new variable of the given type.
virtual VariableElement * clone() const
Make and return a copy of this.
Base class for NcML element concrete classes.
static void setVariableNameProperly(libdap::BaseType *pVar, const std::string &name)
Currently BaseType::set_name only sets in BaseType.
static const string _sTypeName
#define THROW_NCML_INTERNAL_ERROR(msg)
static const vector< string > _sValidAttributes
Concrete class for NcML element.
virtual const string & getTypeName() const
Return the type of the element, which should be: the same as ConcreteClassName::getTypeName() ...
#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.
void setGotValues()
Called once we set the values from ValuesElement so we are aware.
const std::string name() const
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.
static auto_ptr< NCMLBaseArray > createFromArray(const libdap::Array &proto)
Make a new NCMLArray from the given proto, using the Array interface.