30#include <libdap/DDS.h>
32#include "AttributeElement.h"
34#include "NCMLParser.h"
36#include "OtherXMLParser.h"
40#define USE_NC_GLOBAL_CONTAINER 0
43const string AttributeElement::_sTypeName =
"attribute";
44const vector<string> AttributeElement::_sValidAttributes = getValidAttributes();
46const string AttributeElement::_default_global_container =
"NC_GLOBAL";
49AttributeElement::AttributeElement()
50 : NCMLElement(0), _name(
""), _type(
""), _value(
""), _separator(NCMLUtil::WHITESPACE), _orgName(
""), _tokens(),
56AttributeElement::AttributeElement(
const AttributeElement &proto)
57 : RCObjectInterface(), NCMLElement(proto)
61 _value = proto._value;
62 _separator = proto._separator;
63 _orgName = proto._orgName;
64 _tokens = proto._tokens;
68AttributeElement::~AttributeElement()
70 delete _pOtherXMLParser;
74AttributeElement::getTypeName()
const
80AttributeElement::clone()
const
94 validateAttributes(attrs, _sValidAttributes);
98AttributeElement::handleBegin()
100 processAttribute(*_parser);
104AttributeElement::handleContent(
const string &content)
107 if (_parser->isScopeAtomicAttribute()) {
108 BESDEBUG(
"ncml2",
"Adding attribute values as characters content for atomic attribute=" << _name <<
109 " value=\"" << content
114 else if (!NCMLUtil::isAllWhitespace(content)) {
115 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
116 "Got characters content for a non-atomic attribute!"
117 " attribute@value is not allowed for attribute@type=Structure!");
122AttributeElement::handleEnd()
124 processEndAttribute(*_parser);
128AttributeElement::toString()
const
130 string ret =
"<" + _sTypeName +
" ";
132 ret +=
"name=\"" + _name +
"\"";
134 if (!_type.empty()) {
135 ret +=
" type=\"" + _type +
"\" ";
138 if (_separator != NCMLUtil::WHITESPACE) {
139 ret +=
" separator=\"" + _separator +
"\" ";
142 if (!_orgName.empty()) {
143 ret +=
" orgName=\"" + _orgName +
"\" ";
146 if (!_value.empty()) {
147 ret +=
" value=\"" + _value +
"\" ";
159AttributeElement::processAttribute(
NCMLParser &p)
161 BESDEBUG(
"ncml2",
"handleBeginAttribute called for attribute name=" << _name << endl);
165 if (!p.withinNetcdf()) {
166 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
167 "Got <attribute> element while not within a <netcdf> node!");
170 if (p.isScopeAtomicAttribute()) {
171 THROW_NCML_PARSE_ERROR(
172 _parser->getParseLineNumber(),
173 "Got new <attribute> while in a leaf <attribute> at scope=" + p.getScopeString() +
174 " Hierarchies of attributes are only allowed for attribute containers with type=Structure");
180 if (internalType.empty()) {
181 THROW_NCML_PARSE_ERROR(
182 _parser->getParseLineNumber(),
183 "Unknown NCML type=" + _type +
" for attribute name=" + _name +
" at scope=" + p.getScopeString());
189 if (_type == NCMLParser::STRUCTURE_TYPE) {
190 BESDEBUG(
"ncml2",
"Processing an attribute element with type Structure." << endl);
191 processAttributeContainerAtCurrentScope(p);
195 processAtomicAttributeAtCurrentScope(p);
200AttributeElement::processAtomicAttributeAtCurrentScope(NCMLParser &p)
204 if (_orgName.empty()) {
205 if (p.attributeExistsAtCurrentScope(_name)) {
206 BESDEBUG(
"ncml",
"Found existing attribute named: " << _name <<
" with type=" << _type <<
" at scope=" <<
207 p.getScopeString() << endl);
212 BESDEBUG(
"ncml",
"Didn't find attribute: " << _name <<
" so adding it with type=" << _type <<
" and value="
220 renameAtomicAttribute(p);
224 if (_type ==
"OtherXML") {
225 startOtherXMLParse(p);
229 p.enterScope(_name, ScopeStack::ATTRIBUTE_ATOMIC);
233AttributeElement::processAttributeContainerAtCurrentScope(NCMLParser &p)
235 NCML_ASSERT_MSG(_type == NCMLParser::STRUCTURE_TYPE,
236 "Logic error: processAttributeContainerAtCurrentScope called with non Structure type.");
237 BESDEBUG(
"ncml",
"Processing attribute container with name:" << _name << endl);
240 if (!_value.empty()) {
241 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
242 "Found non empty() value attribute for attribute container at scope=" +
243 p.getTypedScopeString());
247 VALID_PTR(p.getCurrentAttrTable());
251 if (!_orgName.empty()) {
252 pAT = renameAttributeContainer(p);
257 AttrTable *pCurrentTable = p.getCurrentAttrTable();
260 pAT = pCurrentTable->simple_find_container(_name);
264 if (p.getVariableInCurrentVariableContainer(_name)) {
265 THROW_NCML_PARSE_ERROR(line(),
266 "Cannot create a new attribute container with name=" + _name +
267 " at current scope since a variable with that name already exists. Scope=" +
272 pAT = pCurrentTable->append_container(_name);
273 BESDEBUG(
"ncml",
"Attribute container was not found, creating new one name=" << _name <<
" at scope="
274 << p.getScopeString() << endl);
278 "Found an attribute container name=" << _name <<
" at scope=" << p.getScopeString() << endl);
284 p.setCurrentAttrTable(pAT);
285 p.enterScope(pAT->get_name(), ScopeStack::ATTRIBUTE_CONTAINER);
289AttributeElement::getInternalType()
const
291 return NCMLParser::convertNcmlTypeToCanonicalType(_type);
295AttributeElement::addNewAttribute(NCMLParser &p)
297 VALID_PTR(p.getCurrentAttrTable());
299 string internalType = getInternalType();
302 if (internalType !=
"OtherXML") {
304 p.tokenizeAttrValues(_tokens, _value, internalType, _separator);
305 BESDEBUG(
"ncml2",
"Adding the attribute '" << _name <<
"' to the current table" << endl);
306 BESDEBUG(
"ncml2",
"The Current attribute table is at: '" << p.getCurrentAttrTable() <<
"'" << endl);
307 p.getCurrentAttrTable()->append_attr(_name, internalType, &(_tokens));
312 BESDEBUG(
"ncml",
"Addinng new attribute of type OtherXML data." << endl);
313 if (!_value.empty()) {
314 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
315 "Adding new Attribute of type=OtherXML: Cannot specify"
316 " an attribute@value for OtherXML --- it must be set in the content! Scope was: "
317 + p.getScopeString());
320 p.getCurrentAttrTable()->append_attr(_name, internalType, _value);
325AttributeElement::mutateAttributeAtCurrentScope(NCMLParser &p,
const string &name,
const string &type,
328 AttrTable *pTable = p.getCurrentAttrTable();
330 NCML_ASSERT_MSG(p.attributeExistsAtCurrentScope(name),
331 "Logic error. mutateAttributeAtCurrentScope called when attribute name=" + name +
332 " didn't exist at scope=" + p.getTypedScopeString());
335 string actualType = type;
337 actualType = pTable->get_type(name);
341 actualType = p.convertNcmlTypeToCanonicalType(actualType);
344 pTable->del_attr(name);
347 if (actualType ==
"OtherXML") {
348 BESDEBUG(
"ncml_attr",
"Setting OtherXML data to: " << endl << _value << endl);
349 pTable->append_attr(name, actualType, _value);
352 p.tokenizeAttrValues(_tokens, value, actualType, _separator);
353#if USE_NC_GLOBAL_CONTAINER
370 BESDEBUG(
"ncml_attr",
"mutateAttributeAtCurrentScope: Looking at table: " << pTable->get_name() << endl);
371 BESDEBUG(
"ncml_attr",
"Looking at attribute named: " << _name << endl);
372 BESDEBUG(
"ncml_attr",
"isScopeGlobal(): " << p.isScopeGlobal() << endl);
373 BESDEBUG(
"ncml_attr",
"isScopeNetcdf(): " << p.isScopeNetcdf() << endl);
374 BESDEBUG(
"ncml_attr",
"isScopeAtomicAttribute(): " << p.isScopeAtomicAttribute() << endl);
375 BESDEBUG(
"ncml_attr",
"isScopeAttributeContainer(): " << p.isScopeAttributeContainer() << endl);
376 BESDEBUG(
"ncml_attr",
"isScopeVariable(): " << p.isScopeVariable() << endl);
377 BESDEBUG(
"ncml_attr",
"getTypedScopeString(): " << p.getTypedScopeString() << endl);
378 BESDEBUG(
"ncml_attr",
"getScopeDepth(): " << p.getScopeDepth() << endl);
379 BESDEBUG(
"ncml_attr",
"DAP version: " << p.getDDSForCurrentDataset()->get_dap_major() <<
"." << p.getDDSForCurrentDataset()->get_dap_minor() << endl);
384 if (p.getScopeDepth() < 2 && p.getDDSForCurrentDataset()->get_dap_major() < 4)
386 BESDEBUG(
"ncml_attr",
"There's no parent container, looking for " << _default_global_container <<
"..." << endl);
391 AttrTable *at = pTable->find_container(_default_global_container);
394 BESDEBUG(
"ncml_attr",
" not found; adding." << endl);
395 at = pTable->append_container(_default_global_container);
399 BESDEBUG(
"ncml_attr",
" found; using" << endl);
402 at->append_attr(_name, actualType, &(_tokens));
406 BESDEBUG(
"ncml_attr",
"Found parent container..." << endl);
407 pTable->append_attr(_name, actualType, &(_tokens));
410 pTable->append_attr(name, actualType, &(_tokens));
416AttributeElement::renameAtomicAttribute(NCMLParser &p)
418 AttrTable *pTable = p.getCurrentAttrTable();
422 if (!p.attributeExistsAtCurrentScope(_orgName)) {
423 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
424 "Failed to change name of non-existent attribute with orgName=" + _orgName +
425 " and new name=" + _name +
" at the current scope=" + p.getScopeString());
430 if (p.isNameAlreadyUsedAtCurrentScope(_name)) {
431 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
432 "Failed to change name of existing attribute orgName=" + _orgName +
433 " because an attribute or variable with the new name=" + _name +
434 " already exists at the current scope=" + p.getScopeString());
437 AttrTable::Attr_iter it;
438 bool gotIt = p.findAttribute(_orgName, it);
442 NCML_ASSERT_MSG(!pTable->is_container(it),
443 "LOGIC ERROR: renameAtomicAttribute() got an attribute container where it expected an atomic attribute!");
446 vector<string> *pAttrVec = pTable->get_attr_vector(it);
447 NCML_ASSERT_MSG(pAttrVec,
"Unexpected NULL from get_attr_vector()");
449 vector<string> orgData = *pAttrVec;
450 AttrType orgType = pTable->get_attr_type(it);
453 pTable->del_attr(_orgName);
456 string typeToUse = AttrType_to_String(orgType);
457 if (!_type.empty() && _type != typeToUse) {
458 BESDEBUG(
"ncml",
"Warning: renameAtomicAttribute(). New type did not match old type, using new type." << endl);
465 pTable->append_attr(_name, typeToUse, &orgData);
469 if (!_value.empty()) {
470 mutateAttributeAtCurrentScope(p, _name, typeToUse, _value);
475AttributeElement::renameAttributeContainer(NCMLParser &p)
477 AttrTable *pTable = p.getCurrentAttrTable();
479 AttrTable *pAT = pTable->simple_find_container(_orgName);
481 THROW_NCML_PARSE_ERROR(line(),
482 "renameAttributeContainer: Failed to find attribute container with orgName=" + _orgName +
483 " at scope=" + p.getScopeString());
486 if (p.isNameAlreadyUsedAtCurrentScope(_name)) {
487 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
488 "Renaming attribute container with orgName=" + _orgName +
489 " to new name=" + _name +
490 " failed since an attribute or variable already exists with that name at scope=" +
494 BESDEBUG(
"ncml",
"Renaming attribute container orgName=" << _orgName <<
" to name=" << _name <<
" at scope="
495 << p.getTypedScopeString() << endl);
498 AttrTable::Attr_iter it;
499 bool gotIt = p.findAttribute(_orgName, it);
500 NCML_ASSERT_MSG(gotIt,
"Logic error. renameAttributeContainer expected to find attribute but didn't.");
503 pTable->del_attr_table(it);
506 pAT->set_name(_name);
507 pTable->append_container(pAT, _name);
514AttributeElement::processEndAttribute(NCMLParser &p)
517 BESDEBUG(
"ncml",
"AttributeElement::handleEnd called at scope:" << p.getScopeString() << endl);
519 if (p.isScopeAtomicAttribute()) {
521 if (_type ==
"OtherXML") {
522 VALID_PTR(_pOtherXMLParser);
523 _value = _pOtherXMLParser->getString();
524 SAFE_DELETE(_pOtherXMLParser);
528 if (_orgName.empty() ||
529 (!_orgName.empty() && !_value.empty())) {
530 mutateAttributeAtCurrentScope(*_parser, _name, _type, _value);
535 else if (p.isScopeAttributeContainer()) {
537 VALID_PTR(p.getCurrentAttrTable());
538 p.setCurrentAttrTable(p.getCurrentAttrTable()->get_parent());
540 NCML_ASSERT_MSG(p.getCurrentAttrTable(),
541 "ERROR: Null p.getCurrentAttrTable() unexpected while leaving scope of attribute container!");
545 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
546 "Got end of attribute element while not parsing an attribute!");
551AttributeElement::startOtherXMLParse(NCMLParser &p)
554 _pOtherXMLParser =
new OtherXMLParser(p);
555 p.enterOtherXMLParsingState(_pOtherXMLParser);
559AttributeElement::getValidAttributes()
561 vector<string> attrs;
563 attrs.push_back(
"name");
564 attrs.push_back(
"type");
565 attrs.push_back(
"value");
566 attrs.push_back(
"orgName");
567 attrs.push_back(
"separator");
Concrete class for NcML <attribute> element.
static string convertNcmlTypeToCanonicalType(const string &ncmlType)
const std::string getValueForLocalNameOrDefault(const std::string &localname, const std::string &defVal="") const
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...