32 #include "AttributeElement.h"
33 #include "NCMLDebug.h"
34 #include "NCMLParser.h"
36 #include "OtherXMLParser.h"
40 #define USE_NC_GLOBAL_CONTAINER 0
44 const string AttributeElement::_sTypeName =
"attribute";
45 const vector<string> AttributeElement::_sValidAttributes = getValidAttributes();
47 const string AttributeElement::_default_global_container =
"NC_GLOBAL";
49 AttributeElement::AttributeElement()
54 , _separator(NCMLUtil::WHITESPACE)
62 AttributeElement::AttributeElement(
const AttributeElement& proto)
68 _value = proto._value;
69 _separator = proto._separator;
70 _orgName = proto._orgName;
71 _tokens = proto._tokens;
75 AttributeElement::~AttributeElement()
77 delete _pOtherXMLParser;
81 AttributeElement::getTypeName()
const
87 AttributeElement::clone()
const
101 validateAttributes(attrs, _sValidAttributes);
105 AttributeElement::handleBegin()
107 processAttribute(*_parser);
111 AttributeElement::handleContent(
const string& content)
114 if (_parser->isScopeAtomicAttribute())
116 BESDEBUG(
"ncml2",
"Adding attribute values as characters content for atomic attribute=" << _name <<
117 " value=\"" << content <<
"\"" << endl);
121 else if (!NCMLUtil::isAllWhitespace(content))
123 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
124 "Got characters content for a non-atomic attribute!"
125 " attribute@value is not allowed for attribute@type=Structure!");
130 AttributeElement::handleEnd()
132 processEndAttribute(*_parser);
136 AttributeElement::toString()
const
138 string ret =
"<" + _sTypeName +
" ";
140 ret +=
"name=\"" + _name +
"\"";
144 ret +=
" type=\"" + _type +
"\" ";
147 if (_separator != NCMLUtil::WHITESPACE)
149 ret +=
" separator=\"" + _separator +
"\" ";
152 if (!_orgName.empty())
154 ret +=
" orgName=\"" + _orgName +
"\" ";
159 ret +=
" value=\"" + _value +
"\" ";
171 AttributeElement::processAttribute(
NCMLParser& p)
173 BESDEBUG(
"ncml2",
"handleBeginAttribute called for attribute name=" << _name << endl);
177 if (!p.withinNetcdf())
179 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
180 "Got <attribute> element while not within a <netcdf> node!");
183 if (p.isScopeAtomicAttribute())
185 THROW_NCML_PARSE_ERROR(
186 _parser->getParseLineNumber(),
187 "Got new <attribute> while in a leaf <attribute> at scope=" + p.getScopeString() +
188 " Hierarchies of attributes are only allowed for attribute containers with type=Structure");
194 if (internalType.empty())
196 THROW_NCML_PARSE_ERROR(
197 _parser->getParseLineNumber(),
198 "Unknown NCML type=" + _type +
" for attribute name=" + _name +
" at scope=" + p.getScopeString());
204 if (_type == NCMLParser::STRUCTURE_TYPE)
206 BESDEBUG(
"ncml2",
"Processing an attribute element with type Structure." << endl);
207 processAttributeContainerAtCurrentScope(p);
211 processAtomicAttributeAtCurrentScope(p);
216 AttributeElement::processAtomicAttributeAtCurrentScope(NCMLParser& p)
220 if (_orgName.empty())
222 if (p.attributeExistsAtCurrentScope(_name))
224 BESDEBUG(
"ncml",
"Found existing attribute named: " << _name <<
" with type=" << _type <<
" at scope=" <<
225 p.getScopeString() << endl);
231 BESDEBUG(
"ncml",
"Didn't find attribute: " << _name <<
" so adding it with type=" << _type <<
" and value=" << _value << endl );
238 renameAtomicAttribute(p);
242 if (_type ==
"OtherXML")
244 startOtherXMLParse(p);
248 p.enterScope(_name, ScopeStack::ATTRIBUTE_ATOMIC);
252 AttributeElement::processAttributeContainerAtCurrentScope(NCMLParser& p)
254 NCML_ASSERT_MSG(_type == NCMLParser::STRUCTURE_TYPE,
"Logic error: processAttributeContainerAtCurrentScope called with non Structure type.");
255 BESDEBUG(
"ncml",
"Processing attribute container with name:" << _name << endl);
260 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
261 "Found non empty() value attribute for attribute container at scope=" + p.getTypedScopeString());
265 VALID_PTR(p.getCurrentAttrTable());
269 if (!_orgName.empty())
271 pAT = renameAttributeContainer(p);
276 AttrTable* pCurrentTable = p.getCurrentAttrTable();
279 pAT = pCurrentTable->simple_find_container(_name);
283 if (p.getVariableInCurrentVariableContainer(_name))
285 THROW_NCML_PARSE_ERROR(line(),
286 "Cannot create a new attribute container with name=" + _name +
287 " at current scope since a variable with that name already exists. Scope=" +
292 pAT = pCurrentTable->append_container(_name);
293 BESDEBUG(
"ncml",
"Attribute container was not found, creating new one name=" << _name <<
" at scope=" << p.getScopeString() << endl);
297 BESDEBUG(
"ncml",
"Found an attribute container name=" << _name <<
" at scope=" << p.getScopeString() << endl);
303 p.setCurrentAttrTable(pAT);
304 p.enterScope(pAT->get_name(), ScopeStack::ATTRIBUTE_CONTAINER);
308 AttributeElement::getInternalType()
const
310 return NCMLParser::convertNcmlTypeToCanonicalType(_type);
314 AttributeElement::addNewAttribute(NCMLParser& p)
316 VALID_PTR(p.getCurrentAttrTable());
318 string internalType = getInternalType();
321 if (internalType !=
"OtherXML")
324 p.tokenizeAttrValues(_tokens, _value, internalType, _separator);
325 BESDEBUG(
"ncml2",
"Adding the attribute '" << _name <<
"' to the current table" << endl);
326 BESDEBUG(
"ncml2",
"The Current attribute table is at: '" << p.getCurrentAttrTable() <<
"'" << endl);
327 p.getCurrentAttrTable()->append_attr(_name, internalType, &(_tokens));
332 BESDEBUG(
"ncml",
"Addinng new attribute of type OtherXML data." << endl);
335 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
336 "Adding new Attribute of type=OtherXML: Cannot specify"
337 " an attribute@value for OtherXML --- it must be set in the content! Scope was: "
338 + p.getScopeString() );
341 p.getCurrentAttrTable()->append_attr(_name, internalType, _value);
346 AttributeElement::mutateAttributeAtCurrentScope(NCMLParser& p,
const string& name,
const string& type,
const string& value)
348 AttrTable* pTable = p.getCurrentAttrTable();
350 NCML_ASSERT_MSG(p.attributeExistsAtCurrentScope(name),
351 "Logic error. mutateAttributeAtCurrentScope called when attribute name=" + name +
" didn't exist at scope=" + p.getTypedScopeString());
354 string actualType = type;
357 actualType = pTable->get_type(name);
361 actualType = p.convertNcmlTypeToCanonicalType(actualType);
364 pTable->del_attr(name);
367 if (actualType ==
"OtherXML")
369 BESDEBUG(
"ncml_attr",
"Setting OtherXML data to: " << endl << _value << endl);
370 pTable->append_attr(name, actualType, _value);
374 p.tokenizeAttrValues(_tokens, value, actualType, _separator);
375 #if USE_NC_GLOBAL_CONTAINER
392 BESDEBUG(
"ncml_attr",
"mutateAttributeAtCurrentScope: Looking at table: " << pTable->get_name() << endl);
393 BESDEBUG(
"ncml_attr",
"Looking at attribute named: " << _name << endl);
394 BESDEBUG(
"ncml_attr",
"isScopeGlobal(): " << p.isScopeGlobal() << endl);
395 BESDEBUG(
"ncml_attr",
"isScopeNetcdf(): " << p.isScopeNetcdf() << endl);
396 BESDEBUG(
"ncml_attr",
"isScopeAtomicAttribute(): " << p.isScopeAtomicAttribute() << endl);
397 BESDEBUG(
"ncml_attr",
"isScopeAttributeContainer(): " << p.isScopeAttributeContainer() << endl);
398 BESDEBUG(
"ncml_attr",
"isScopeVariable(): " << p.isScopeVariable() << endl);
399 BESDEBUG(
"ncml_attr",
"getTypedScopeString(): " << p.getTypedScopeString() << endl);
400 BESDEBUG(
"ncml_attr",
"getScopeDepth(): " << p.getScopeDepth() << endl);
401 BESDEBUG(
"ncml_attr",
"DAP version: " << p.getDDSForCurrentDataset()->get_dap_major() <<
"." << p.getDDSForCurrentDataset()->get_dap_minor() << endl);
406 if (p.getScopeDepth() < 2 && p.getDDSForCurrentDataset()->get_dap_major() < 4)
408 BESDEBUG(
"ncml_attr",
"There's no parent container, looking for " << _default_global_container <<
"..." << endl);
413 AttrTable *at = pTable->find_container(_default_global_container);
416 BESDEBUG(
"ncml_attr",
" not found; adding." << endl);
417 at = pTable->append_container(_default_global_container);
421 BESDEBUG(
"ncml_attr",
" found; using" << endl);
424 at->append_attr(_name, actualType, &(_tokens));
428 BESDEBUG(
"ncml_attr",
"Found parent container..." << endl);
429 pTable->append_attr(_name, actualType, &(_tokens));
432 pTable->append_attr(name, actualType, &(_tokens));
438 AttributeElement::renameAtomicAttribute(NCMLParser& p)
440 AttrTable* pTable = p.getCurrentAttrTable();
444 if (!p.attributeExistsAtCurrentScope(_orgName))
446 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
447 "Failed to change name of non-existent attribute with orgName=" + _orgName +
448 " and new name=" + _name +
" at the current scope=" + p.getScopeString());
453 if (p.isNameAlreadyUsedAtCurrentScope(_name))
455 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
456 "Failed to change name of existing attribute orgName=" + _orgName +
457 " because an attribute or variable with the new name=" + _name +
458 " already exists at the current scope=" + p.getScopeString());
461 AttrTable::Attr_iter it;
462 bool gotIt = p.findAttribute(_orgName, it);
466 NCML_ASSERT_MSG( !pTable->is_container(it),
467 "LOGIC ERROR: renameAtomicAttribute() got an attribute container where it expected an atomic attribute!");
470 vector<string>* pAttrVec = pTable->get_attr_vector(it);
471 NCML_ASSERT_MSG(pAttrVec,
"Unexpected NULL from get_attr_vector()");
473 vector<string> orgData = *pAttrVec;
474 AttrType orgType = pTable->get_attr_type(it);
477 pTable->del_attr(_orgName);
480 string typeToUse = AttrType_to_String(orgType);
481 if (!_type.empty() && _type != typeToUse)
483 BESDEBUG(
"ncml",
"Warning: renameAtomicAttribute(). New type did not match old type, using new type." << endl);
490 pTable->append_attr(_name, typeToUse, &orgData);
496 mutateAttributeAtCurrentScope(p, _name, typeToUse, _value);
501 AttributeElement::renameAttributeContainer(NCMLParser& p)
503 AttrTable* pTable = p.getCurrentAttrTable();
505 AttrTable* pAT = pTable->simple_find_container(_orgName);
508 THROW_NCML_PARSE_ERROR(line(),
509 "renameAttributeContainer: Failed to find attribute container with orgName=" + _orgName +
510 " at scope=" + p.getScopeString());
513 if (p.isNameAlreadyUsedAtCurrentScope(_name))
515 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
516 "Renaming attribute container with orgName=" + _orgName +
517 " to new name=" + _name +
518 " failed since an attribute or variable already exists with that name at scope=" + p.getScopeString());
521 BESDEBUG(
"ncml",
"Renaming attribute container orgName=" << _orgName <<
" to name=" << _name <<
" at scope="
522 << p.getTypedScopeString() << endl);
525 AttrTable::Attr_iter it;
526 bool gotIt = p.findAttribute(_orgName, it);
527 NCML_ASSERT_MSG(gotIt,
"Logic error. renameAttributeContainer expected to find attribute but didn't.");
530 pTable->del_attr_table(it);
533 pAT->set_name(_name);
534 pTable->append_container(pAT, _name);
541 AttributeElement::processEndAttribute(NCMLParser& p)
544 BESDEBUG(
"ncml",
"AttributeElement::handleEnd called at scope:" << p.getScopeString() << endl);
546 if (p.isScopeAtomicAttribute())
549 if (_type ==
"OtherXML")
551 VALID_PTR(_pOtherXMLParser);
552 _value = _pOtherXMLParser->getString();
553 SAFE_DELETE(_pOtherXMLParser);
557 if (_orgName.empty() ||
558 (!_orgName.empty() && !_value.empty()) )
560 mutateAttributeAtCurrentScope(*_parser, _name, _type, _value);
565 else if (p.isScopeAttributeContainer())
568 VALID_PTR(p.getCurrentAttrTable());
569 p.setCurrentAttrTable(p.getCurrentAttrTable()->get_parent());
571 NCML_ASSERT_MSG(p.getCurrentAttrTable(),
"ERROR: Null p.getCurrentAttrTable() unexpected while leaving scope of attribute container!");
575 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
576 "Got end of attribute element while not parsing an attribute!");
581 AttributeElement::startOtherXMLParse(NCMLParser& p)
584 _pOtherXMLParser =
new OtherXMLParser(p);
585 p.enterOtherXMLParsingState(_pOtherXMLParser);
589 AttributeElement::getValidAttributes()
591 vector<string> attrs;
593 attrs.push_back(
"name");
594 attrs.push_back(
"type");
595 attrs.push_back(
"value");
596 attrs.push_back(
"orgName");
597 attrs.push_back(
"separator");