libdap Updated for version 3.21.0
libdap4 is an implementation of OPeNDAP's DAP protocol.
AttrTable.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of libdap, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 2002,2003 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// (c) COPYRIGHT URI/MIT 1994-1999
26// Please read the full copyright statement in the file COPYRIGHT_URI.
27//
28// Authors:
29// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
30
31// jhrg 7/29/94
32
33#include "config.h"
34
35#include <cassert>
36#include <sstream>
37
38#include "AttrTable.h"
39
40#include "util.h"
41#include "escaping.h"
42#include "DapIndent.h"
43
44#include "debug.h"
45
46// Should the www2id and id2www functions be used to encode attribute names?
47// Probably not... jhrg 11/16/11
48#define WWW_ENCODING 0
49// See the note for del_attr_table(). That method now deletes the contained
50// AttrTable.
51#define NEW_DEL_ATTR_TABLE_BEHAVIOR 0
52
53using std::cerr;
54using std::string;
55using std::endl;
56using std::vector;
57
58namespace libdap {
59
61string remove_space_encoding(const string &s)
62{
63 string::size_type pos = s.find("%20");
64 if (pos != string::npos) {
65 string n = s;
66 do {
67 n.replace(pos, 3, " ");
68 pos = n.find("%20");
69 } while (pos != string::npos);
70 return n;
71 }
72 else {
73 return s;
74 }
75}
76
78string add_space_encoding(const string &s)
79{
80 string::size_type pos = s.find(" ");
81 if (pos != string::npos) {
82 string n = s;
83 do {
84 n.replace(pos, 1, "%20");
85 pos = n.find(" ");
86 } while (pos != string::npos);
87 return n;
88 }
89 else {
90 return s;
91 }
92}
93
98{
99 switch (at) {
100 case Attr_container:
101 return "Container";
102 case Attr_byte:
103 return "Byte";
104 case Attr_int16:
105 return "Int16";
106 case Attr_uint16:
107 return "UInt16";
108 case Attr_int32:
109 return "Int32";
110 case Attr_uint32:
111 return "UInt32";
112 case Attr_float32:
113 return "Float32";
114 case Attr_float64:
115 return "Float64";
116 case Attr_string:
117 return "String";
118 case Attr_url:
119 return "Url";
120 case Attr_other_xml:
121 return "OtherXML";
122 //
123 // Added for DAP4
124 case Attr_int8:
125 return "Int8";
126 case Attr_uint8:
127 return "UInt8";
128 case Attr_int64:
129 return "Int64";
130 case Attr_uint64:
131 return "UInt64";
132 case Attr_enum:
133 return "Enumeration";
134 case Attr_opaque:
135 return "Opaque";
136 default:
137 return "";
138 }
139}
140
141AttrType String_to_AttrType(const string &s)
142{
143 string s2 = s;
144 downcase(s2);
145
146 if (s2 == "container")
147 return Attr_container;
148 else if (s2 == "byte")
149 return Attr_byte;
150 else if (s2 == "int16")
151 return Attr_int16;
152 else if (s2 == "uint16")
153 return Attr_uint16;
154 else if (s2 == "int32")
155 return Attr_int32;
156 else if (s2 == "uint32")
157 return Attr_uint32;
158 else if (s2 == "float32")
159 return Attr_float32;
160 else if (s2 == "float64")
161 return Attr_float64;
162 else if (s2 == "string")
163 return Attr_string;
164 else if (s2 == "url")
165 return Attr_url;
166 else if (s2 == "otherxml")
167 return Attr_other_xml;
168 //
169 // Added for DAP4
170 else if (s2 == "int8")
171 return Attr_int8;
172 else if (s2 == "uint8")
173 return Attr_uint8;
174 else if (s2 == "int64")
175 return Attr_int64;
176 else if (s2 == "uint64")
177 return Attr_uint64;
178 else if (s2 == "enumeration")
179 return Attr_enum;
180 else if (s2 == "opaque")
181 return Attr_opaque;
182 else
183 return Attr_unknown;
184}
185
188void AttrTable::clone(const AttrTable &at)
189{
190 d_name = at.d_name;
191 d_is_global_attribute = at.d_is_global_attribute;
192
193 // Set the parent to null (no parent, not in container)
194 // since using at.d_parent is semantically incorrect
195 // and potentially dangerous.
196 d_parent = 0;
197
198 Attr_citer i = at.attr_map.begin();
199 Attr_citer ie = at.attr_map.end();
200 for (; i != ie; ++i) {
201 // this deep-copies containers recursively
202 entry *e = new entry(*(*i));
203 attr_map.push_back(e);
204
205 // If the entry being added was a container,
206 // set its parent to this to maintain invariant.
207 if (e->type == Attr_container) {
208 assert(e->attributes);
209 e->attributes->d_parent = this;
210 }
211 }
212}
213
215
217AttrTable::AttrTable() :
218 DapObj(), d_name(""), d_parent(0), attr_map(), d_is_global_attribute(true)
219{
220}
221
222AttrTable::AttrTable(const AttrTable &rhs) :
223 DapObj()
224{
225 clone(rhs);
226}
227
228// Private
229void AttrTable::delete_attr_table()
230{
231 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
232 delete *i;
233 }
234 attr_map.clear();
235}
236
237AttrTable::~AttrTable()
238{
239 delete_attr_table();
240}
241
242AttrTable &
243AttrTable::operator=(const AttrTable &rhs)
244{
245 if (this != &rhs) {
246 delete_attr_table();
247 clone(rhs);
248 }
249
250 return *this;
251}
253
259unsigned int AttrTable::get_size() const
260{
261 return attr_map.size();
262}
263
267{
268 return d_name;
269}
270
273void AttrTable::set_name(const string &n)
274{
275#if WWW_ENCODING
276 d_name = www2id(n);
277#else
278 d_name = remove_space_encoding(n);
279#endif
280}
281
282#if 0
283// This was taken from das.y and could be used here to make the 'dods_errors'
284// attribute container like the parser used to. Then again, maybe this feature
285// was just BS. jhrg (ticket 1469)
286static void add_bad_attribute(AttrTable *attr, const string &type, const string &name, const string &value,
287 const string &msg) {
288 // First, if this bad value is already in a *_dods_errors container,
289 // then just add it. This can happen when the server side processes a DAS
290 // and then hands it off to a client which does the same.
291 // Make a new container. Call it <attr's name>_errors. If that container
292 // already exists, use it.
293 // Add the attribute.
294 // Add the error string to an attribute in the container called
295 // `<name_explanation.'.
296
297 if (attr->get_name().find("_dods_errors") != string::npos) {
298 attr->append_attr(name, type, value);
299 }
300 else {
301 // I think _dods_errors should be _dap_error. jhrg 11/16/11
302 string error_cont_name = attr->get_name() + "_dods_errors";
303 AttrTable *error_cont = attr->get_attr_table(error_cont_name);
304 if (!error_cont)
305 error_cont = attr->append_container(error_cont_name);
306
307 error_cont->append_attr(name, type, value);
308
309#ifndef ATTR_STRING_QUOTE_FIX
310 error_cont->append_attr(name + "_dap_explanation", "String", "\"" + msg + "\"");
311#else
312 error_cont->append_attr(name + "_dap_explanation", "String", msg);
313#endif
314 }
315}
316#endif
317
335unsigned int AttrTable::append_attr(const string &name, const string &type, const string &value)
336{
337 DBG(cerr << "Entering AttrTable::append_attr" << endl);
338#if WWW_ENCODING
339 string lname = www2id(name);
340#else
341 string lname = remove_space_encoding(name);
342#endif
343
344 Attr_iter iter = simple_find(lname);
345
346 // If the types don't match OR this attribute is a container, calling
347 // this mfunc is an error!
348 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
349 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
350 if (iter != attr_map.end() && (get_type(iter) == "Container"))
351 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
352
353 if (iter != attr_map.end()) { // Must be a new attribute value; add it.
354 (*iter)->attr->push_back(value);
355 return (*iter)->attr->size();
356 }
357 else { // Must be a completely new attribute; add it
358 entry *e = new entry;
359
360 e->name = lname;
361 e->is_alias = false;
362 e->type = String_to_AttrType(type); // Record type using standard names.
363 e->attr = new vector<string> ;
364 e->attr->push_back(value);
365
366 attr_map.push_back(e);
367
368 return e->attr->size(); // return the length of the attr vector
369 }
370}
371
389
390unsigned int AttrTable::append_attr(const string &name, const string &type, vector<string> *values)
391{
392 DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl);
393#if WWW_ENCODING
394 string lname = www2id(name);
395#else
396 string lname = remove_space_encoding(name);
397#endif
398 Attr_iter iter = simple_find(lname);
399
400 // If the types don't match OR this attribute is a container, calling
401 // this mfunc is an error!
402 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
403 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
404 if (iter != attr_map.end() && (get_type(iter) == "Container"))
405 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
406
407 if (iter != attr_map.end()) { // Must be new attribute values; add.
408 vector<string>::iterator i = values->begin();
409 while (i != values->end())
410 (*iter)->attr->push_back(*i++);
411
412 return (*iter)->attr->size();
413 }
414 else { // Must be a completely new attribute; add it
415 entry *e = new entry;
416
417 e->name = lname;
418 e->is_alias = false;
419 e->type = String_to_AttrType(type); // Record type using standard names.
420 e->attr = new vector<string> (*values);
421
422 attr_map.push_back(e);
423
424 return e->attr->size(); // return the length of the attr vector
425 }
426}
427
446unsigned int AttrTable::append_attr(const string &name, const string &type, const string &value, bool is_utf8_str)
447{
448 DBG(cerr << "Entering AttrTable::append_attr" << endl);
449#if WWW_ENCODING
450 string lname = www2id(name);
451#else
452 string lname = remove_space_encoding(name);
453#endif
454
455 Attr_iter iter = simple_find(lname);
456
457 // If the types don't match OR this attribute is a container, calling
458 // this mfunc is an error!
459 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
460 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
461 if (iter != attr_map.end() && (get_type(iter) == "Container"))
462 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
463
464 if (iter != attr_map.end()) { // Must be a new attribute value; add it.
465 (*iter)->attr->push_back(value);
466 (*iter)->is_utf8_str = is_utf8_str;
467 return (*iter)->attr->size();
468 }
469 else { // Must be a completely new attribute; add it
470 entry *e = new entry;
471
472 e->name = lname;
473 e->is_alias = false;
474 e->type = String_to_AttrType(type); // Record type using standard names.
475 e->is_utf8_str = is_utf8_str;
476 e->attr = new vector<string> ;
477 e->attr->push_back(value);
478
479 attr_map.push_back(e);
480
481 return e->attr->size(); // return the length of the attr vector
482 }
483}
484
503
504unsigned int AttrTable::append_attr(const string &name, const string &type, vector<string> *values, bool is_utf8_str)
505{
506 DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl);
507#if WWW_ENCODING
508 string lname = www2id(name);
509#else
510 string lname = remove_space_encoding(name);
511#endif
512 Attr_iter iter = simple_find(lname);
513
514 // If the types don't match OR this attribute is a container, calling
515 // this mfunc is an error!
516 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
517 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
518 if (iter != attr_map.end() && (get_type(iter) == "Container"))
519 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
520
521 if (iter != attr_map.end()) { // Must be new attribute values; add.
522 vector<string>::iterator i = values->begin();
523 while (i != values->end())
524 (*iter)->attr->push_back(*i++);
525 (*iter)->is_utf8_str = is_utf8_str;
526 return (*iter)->attr->size();
527 }
528 else { // Must be a completely new attribute; add it
529 entry *e = new entry;
530
531 e->name = lname;
532 e->is_alias = false;
533 e->type = String_to_AttrType(type); // Record type using standard names.
534 e->is_utf8_str = is_utf8_str;
535 e->attr = new vector<string> (*values);
536
537 attr_map.push_back(e);
538
539 return e->attr->size(); // return the length of the attr vector
540 }
541}
542
543
552
553AttrTable *
555{
556 AttrTable *new_at = new AttrTable;
557 AttrTable *ret = NULL;
558 try {
559 ret = append_container(new_at, name);
560 } catch (Error &e) {
561 // an error occurred, attribute with that name already exists
562 delete new_at;
563 new_at = 0;
564 throw;
565 }
566 return ret;
567}
568
583AttrTable *
584AttrTable::append_container(AttrTable *at, const string &name)
585{
586#if WWW_ENCODING
587 string lname = www2id(name);
588#else
589 string lname = remove_space_encoding(name);
590#endif
591
592 if (simple_find(name) != attr_end())
593 throw Error("There already exists a container called '" + name + "' in this attribute table (" + at->get_name() + "). (1)");
594
595 DBG(cerr << "Setting appended attribute container name to: " << lname << endl);
596 at->set_name(lname);
597
598 entry *e = new entry;
599 e->name = lname;
600 e->is_alias = false;
601 e->type = Attr_container;
602 e->attributes = at;
603
604 attr_map.push_back(e);
605
606 at->d_parent = this;
607
608 return e->attributes;
609}
610
625void AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter)
626{
627 string::size_type dotpos = target.rfind('.');
628 if (dotpos != string::npos) {
629 string container = target.substr(0, dotpos);
630 string field = target.substr(dotpos + 1);
631
632 *at = find_container(container);
633 if (*at) {
634 *iter = (*at)->simple_find(field);
635 }
636 else {
637 *iter = attr_map.end();
638 }
639 }
640 else {
641 *at = recurrsive_find(target, iter);
642 }
643}
644
656AttrTable *
657AttrTable::recurrsive_find(const string &target, Attr_iter *location)
658{
659 Attr_iter i = attr_begin();
660 while (i != attr_end()) {
661 if (target == (*i)->name) {
662 *location = i;
663 return this;
664 }
665 else if ((*i)->type == Attr_container) {
666 AttrTable *at = (*i)->attributes->recurrsive_find(target, location);
667 if (at)
668 return at;
669 }
670
671 ++i;
672 }
673
674 *location = i;
675 return 0;
676}
677
678// Made public for callers that want non-recursive find. [mjohnson 6 oct 09]
685AttrTable::Attr_iter AttrTable::simple_find(const string &target)
686{
687 Attr_iter i;
688 for (i = attr_map.begin(); i != attr_map.end(); ++i) {
689 if (target == (*i)->name) {
690 break;
691 }
692 }
693 return i;
694}
695
709AttrTable *
710AttrTable::find_container(const string &target)
711{
712 string::size_type dotpos = target.find('.');
713 if (dotpos != string::npos) {
714 string container = target.substr(0, dotpos);
715 string field = target.substr(dotpos + 1);
716
717 AttrTable *at = simple_find_container(container);
718 return (at) ? at->find_container(field) : 0;
719 }
720 else {
721 return simple_find_container(target);
722 }
723}
724
725// Made public for callers that want non-recursive find. [mjohnson 6 oct 09]
726AttrTable *
727AttrTable::simple_find_container(const string &target)
728{
729 if (get_name() == target)
730 return this;
731
732 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
733 if (is_container(i) && target == (*i)->name) {
734 return (*i)->attributes;
735 }
736 }
737
738 return 0;
739}
740
748
750AttrTable *
751AttrTable::get_attr_table(const string &name)
752{
753 return find_container(name);
754}
755
757string AttrTable::get_type(const string &name)
758{
759 Attr_iter p = simple_find(name);
760 return (p != attr_map.end()) ? get_type(p) : (string) "";
761}
762
766{
767 Attr_iter p = simple_find(name);
768 return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown;
769}
770
778unsigned int AttrTable::get_attr_num(const string &name)
779{
780 Attr_iter iter = simple_find(name);
781 return (iter != attr_map.end()) ? get_attr_num(iter) : 0;
782}
783
796vector<string> *
797AttrTable::get_attr_vector(const string &name)
798{
799 Attr_iter p = simple_find(name);
800 return (p != attr_map.end()) ? get_attr_vector(p) : 0;
801}
802
819void AttrTable::del_attr(const string &name, int i)
820{
821#if WWW_ENCODING
822 string lname = www2id(name);
823#else
824 string lname = remove_space_encoding(name);
825#endif
826
827 Attr_iter iter = simple_find(lname);
828 if (iter != attr_map.end()) {
829 if (i == -1) { // Delete the whole attribute
830 entry *e = *iter;
831 attr_map.erase(iter);
832 delete e;
833 e = 0;
834 }
835 else { // Delete one element from attribute array
836 // Don't try to delete elements from the vector of values if the
837 // map is a container!
838 if ((*iter)->type == Attr_container)
839 return;
840
841 vector<string> *sxp = (*iter)->attr;
842
843 assert(i >= 0 && i < (int) sxp->size());
844 sxp->erase(sxp->begin() + i); // rm the element
845 }
846 }
847}
848
850
853
855AttrTable::Attr_iter AttrTable::attr_begin()
856{
857 return attr_map.begin();
858}
859
863AttrTable::Attr_iter AttrTable::attr_end()
864{
865 return attr_map.end();
866}
867
876AttrTable::Attr_iter AttrTable::get_attr_iter(int i)
877{
878 return attr_map.begin() + i;
879}
880
882string AttrTable::get_name(Attr_iter iter)
883{
884 assert(iter != attr_map.end());
885
886 return (*iter)->name;
887}
888
890bool AttrTable::is_container(Attr_iter i)
891{
892 return (*i)->type == Attr_container;
893}
894
900AttrTable *
902{
903 assert(iter != attr_map.end());
904 return (*iter)->type == Attr_container ? (*iter)->attributes : 0;
905}
906
925AttrTable::Attr_iter AttrTable::del_attr_table(Attr_iter iter)
926{
927 if ((*iter)->type != Attr_container)
928 return ++iter;
929
930 // the caller intends to delete/reuse the contained AttrTable,
931 // so zero it out so it doesn't get deleted before we delete the entry
932 // [mjohnson]
933 struct entry *e = *iter;
934 // container no longer has a parent.
935 if (e->attributes) {
936 e->attributes->d_parent = 0;
937
938#if NEW_DEL_ATTR_TABLE_BEHAVIOR
939 delete e->attributes;
940#endif
941 e->attributes = 0;
942 }
943
944 delete e;
945
946 return attr_map.erase(iter);
947}
948
952string AttrTable::get_type(Attr_iter iter)
953{
954 assert(iter != attr_map.end());
955 return AttrType_to_String((*iter)->type);
956}
957
962{
963 return (*iter)->type;
964}
965
973unsigned int AttrTable::get_attr_num(Attr_iter iter)
974{
975 assert(iter != attr_map.end());
976 return ((*iter)->type == Attr_container) ? (*iter)->attributes->get_size() : (*iter)->attr->size();
977}
978
995string AttrTable::get_attr(Attr_iter iter, unsigned int i)
996{
997 assert(iter != attr_map.end());
998
999 return (*iter)->type == Attr_container ? (string) "None" : (*(*iter)->attr)[i];
1000}
1001
1002string AttrTable::get_attr(const string &name, unsigned int i)
1003{
1004 Attr_iter p = simple_find(name);
1005 return (p != attr_map.end()) ? get_attr(p, i) : (string) "";
1006}
1007
1019vector<string> *
1021{
1022 assert(iter != attr_map.end());
1023 return (*iter)->type != Attr_container ? (*iter)->attr : 0;
1024}
1025
1026bool AttrTable::is_global_attribute(Attr_iter iter)
1027{
1028 assert(iter != attr_map.end());
1029 if ((*iter)->type == Attr_container)
1030 return (*iter)->attributes->is_global_attribute();
1031 else
1032 return (*iter)->is_global;
1033}
1034
1035void AttrTable::set_is_global_attribute(Attr_iter iter, bool ga)
1036{
1037 assert(iter != attr_map.end());
1038 if ((*iter)->type == Attr_container)
1039 (*iter)->attributes->set_is_global_attribute(ga);
1040 else
1041 (*iter)->is_global = ga;
1042}
1043
1045
1046// Alias an attribute table. The alias should be added to this object.
1052void AttrTable::add_container_alias(const string &name, AttrTable *src)
1053{
1054#if WWW_ENCODING
1055 string lname = www2id(name);
1056#else
1057 string lname = remove_space_encoding(name);
1058#endif
1059
1060 if (simple_find(lname) != attr_end())
1061 throw Error(string("There already exists a container called `") + name + string("in this attribute table. (2)"));
1062
1063 entry *e = new entry;
1064 e->name = lname;
1065 e->is_alias = true;
1066 e->aliased_to = src->get_name();
1067 e->type = Attr_container;
1068
1069 e->attributes = src;
1070
1071 attr_map.push_back(e);
1072}
1073
1086void AttrTable::add_value_alias(AttrTable *das, const string &name, const string &source)
1087{
1088#if WWW_ENCODING
1089 string lname = www2id(name);
1090#else
1091 string lname = remove_space_encoding(name);
1092#endif
1093
1094#if WWW_ENCODING
1095 string lsource = www2id(source);
1096#else
1097 string lsource = remove_space_encoding(source);
1098#endif
1099
1100 // find the container that holds source and its (sources's) iterator
1101 // within that container. Search at the uppermost level of the attribute
1102 // object to find values defined `above' the current container.
1103 AttrTable *at;
1104 Attr_iter iter;
1105 das->find(lsource, &at, &iter);
1106
1107 // If source is not found by looking at the topmost level, look in the
1108 // current table (i.e., alias z x where x is in the current container
1109 // won't be found by looking for `x' at the top level). See test case 26
1110 // in das-testsuite.
1111 if (!at || (iter == at->attr_end()) || !*iter) {
1112 find(lsource, &at, &iter);
1113 if (!at || (iter == at->attr_end()) || !*iter)
1114 throw Error(string("Could not find the attribute `") + source + string("' in the attribute object."));
1115 }
1116
1117 // If we've got a value to alias and it's being added at the top level of
1118 // the DAS, that's an error.
1119 if (at && !at->is_container(iter) && this == das)
1120 throw Error(
1121 string(
1122 "A value cannot be aliased to the top level of the DAS;\nOnly containers may be present at that level of the DAS."));
1123
1124 if (simple_find(lname) != attr_end())
1125 throw Error(string("There already exists a container called `") + name + string("in this attribute table. (3)"));
1126
1127 entry *e = new entry;
1128 e->name = lname;
1129 e->is_alias = true;
1130 e->aliased_to = lsource;
1131 e->type = get_attr_type(iter);
1132 if (at && e->type == Attr_container)
1133 e->attributes = at->get_attr_table(iter);
1134 else
1135 e->attr = (*iter)->attr;
1136
1137 attr_map.push_back(e);
1138}
1139
1140// Deprecated
1159bool AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name)
1160{
1161 add_value_alias(at, alias, name);
1162 return true;
1163}
1164
1172bool AttrTable::attr_alias(const string &alias, const string &name)
1173{
1174 return attr_alias(alias, this, name);
1175}
1176
1177
1184bool AttrTable::has_dap4_types(const std::string &path, std::vector<std::string> &inventory) const
1185{
1186 bool has_d4_attr = false;
1187 for(auto attr:attr_map){
1188 string attr_fqn = path + "@" + attr->name;
1189 bool isa_d4_attr = attr->is_dap4_type(attr_fqn, inventory);
1190 if(isa_d4_attr){
1191 inventory.emplace_back(AttrType_to_String(attr->type) + " " + attr_fqn);
1192 }
1193 has_d4_attr |= isa_d4_attr;
1194 }
1195 return has_d4_attr;
1196}
1197
1198
1203{
1204 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1205 delete *i;
1206 *i = 0;
1207 }
1208
1209 attr_map.erase(attr_map.begin(), attr_map.end());
1210
1211 d_name = "";
1212}
1213
1214const string double_quote = "\"";
1215
1216// This is here as a result of the problem described in ticket #1163 where
1217// the data handlers are adding quotes to string attributes so the DAS will
1218// be printed correctly. But that has the affect of adding the quotes to the
1219// attribute's _value_ not just it's print representation. As part of the fix
1220// I made the code here add the quotes if the handlers are fixed (but not if
1221// handlers are still adding them). The other part of 1163 is to fix all of
1222// the handlers... What this fix means is that attributes whose values really
1223// do contain bracketing quotes might be misunderstood, since we're assuming
1224// those quotes were added by the handlers as a hack to get the output
1225// formatting correct for the DAS. jhrg 7/30/08
1226
1227static void write_string_attribute_for_das(ostream &out, const string &value, const string &term, bool is_utf8_str)
1228{
1229
1230 string esc_value = is_utf8_str?value:escattr(value);
1231#if 0
1232 string esc_value = escattr(value);
1233#endif
1234
1235 // The value is already escaped so the following check is not necessary. KY 2022-08-22
1236#if 0
1237 if (is_quoted(esc_value))
1238 out << esc_value << term;
1239 else
1240#endif
1241 out << double_quote << esc_value << double_quote << term;
1242}
1243
1244#if 0
1245static void
1246write_string_attribute_for_das(FILE *out, const string &value, const string &term)
1247{
1248 if (is_quoted(value))
1249 fprintf(out, "%s%s", value.c_str(), term.c_str());
1250 else
1251 fprintf(out, "\"%s\"%s", value.c_str(), term.c_str());
1252}
1253#endif
1254
1255// Special treatment for XML: Make sure to escape double quotes when XML is
1256// printed in a DAS.
1257static void write_xml_attribute_for_das(ostream &out, const string &value, const string &term)
1258{
1259 if (is_quoted(value))
1260 out << escape_double_quotes(value) << term;
1261 else
1262 out << double_quote << escape_double_quotes(value) << double_quote << term;
1263}
1264
1265#if 0
1266static void
1267write_xml_attribute_for_das(FILE *out, const string &value, const string &term)
1268{
1269 if (is_quoted(value))
1270 fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str());
1271 else
1272 fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str());
1273}
1274#endif
1275
1278void AttrTable::simple_print(FILE *out, string pad, Attr_iter i, bool dereference)
1279{
1280 ostringstream oss;
1281 simple_print(oss, pad, i, dereference);
1282 fwrite(oss.str().data(), 1, oss.str().length(), out);
1283
1284#if 0
1285 switch ((*i)->type) {
1286 case Attr_container:
1287#if WWW_ENCODING
1288 fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str());
1289#else
1290 fprintf(out, "%s%s {\n", pad.c_str(), get_name(i).c_str());
1291#endif
1292 (*i)->attributes->print(out, pad + " ", dereference);
1293
1294 fprintf(out, "%s}\n", pad.c_str());
1295 break;
1296
1297 case Attr_string: {
1298#if WWW_ENCODING
1299 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1300#else
1301 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1302#endif
1303 vector<string> *sxp = (*i)->attr;
1304 vector<string>::iterator last = sxp->end() - 1;
1305 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1306 write_string_attribute_for_das(out, *i, ", ");
1307 }
1308 write_string_attribute_for_das(out, *last, ";\n");
1309 }
1310 break;
1311
1312 case Attr_other_xml: {
1313#if WWW_ENCODING
1314 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1315#else
1316 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1317#endif
1318 vector<string> *sxp = (*i)->attr;
1319 vector<string>::iterator last = sxp->end() - 1;
1320 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1321 write_xml_attribute_for_das(out, *i, ", ");
1322 }
1323 write_xml_attribute_for_das(out, *last, ";\n");
1324 }
1325 break;
1326
1327 default: {
1328#if WWW_ENCODING
1329 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1330#else
1331 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1332#endif
1333
1334 vector<string> *sxp = (*i)->attr;
1335 vector<string>::iterator last = sxp->end() - 1;
1336 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1337 fprintf(out, "%s%s", (*i).c_str(), ", ");
1338 }
1339 fprintf(out, "%s%s", (*last).c_str(), ";\n");
1340 }
1341 break;
1342 }
1343#endif
1344}
1345
1348void AttrTable::simple_print(ostream &out, string pad, Attr_iter i, bool dereference)
1349{
1350 switch ((*i)->type) {
1351 case Attr_container:
1352#if WWW_ENCODING
1353 out << pad << id2www(get_name(i)) << " {\n";
1354#else
1355 out << pad << add_space_encoding(get_name(i)) << " {\n";
1356#endif
1357 (*i)->attributes->print(out, pad + " ", dereference);
1358 out << pad << "}\n";
1359 break;
1360
1361 case Attr_string: {
1362#if WWW_ENCODING
1363 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1364#else
1365 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1366#endif
1367 vector<string> *sxp = (*i)->attr;
1368
1369 vector<string>::iterator last = sxp->end() - 1;
1370 for (vector<string>::iterator i_s = sxp->begin(); i_s != last; ++i_s) {
1371 write_string_attribute_for_das(out, *i_s, ", ",(*i)->is_utf8_str);
1372 }
1373 write_string_attribute_for_das(out, *last, ";\n",(*i)->is_utf8_str);
1374
1375 // The following code is intended to replace the code above.
1376 // However, it causes the obscure test failure at HDF5 handler's t_big_str.h5 DAS test.
1377 // it also causes the 17th etc NcML tests failed.
1378 // Leave here and may check this later. KY 2022-09-22
1379#if 0
1380 for (const auto &attr:(*sxp)) {
1381 if (attr != (*sxp).back())
1382 write_string_attribute_for_das(out, attr, ", ",(*i)->is_utf8_str);
1383 else
1384 write_string_attribute_for_das(out, attr, ";\n",(*i)->is_utf8_str);
1385 }
1386#endif
1387 }
1388 break;
1389
1390 case Attr_other_xml: {
1391#if WWW_ENCODING
1392 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1393#else
1394 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1395#endif
1396 vector<string> *sxp = (*i)->attr;
1397 vector<string>::iterator last = sxp->end() - 1;
1398 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1399 write_xml_attribute_for_das(out, *i, ", ");
1400 }
1401 write_xml_attribute_for_das(out, *last, ";\n");
1402 }
1403 break;
1404
1405 default: {
1406#if WWW_ENCODING
1407 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1408#else
1409 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1410#endif
1411 vector<string> *sxp = (*i)->attr;
1412 vector<string>::iterator last = sxp->end() - 1;
1413 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1414 out << *i << ", ";
1415 }
1416 out << *last << ";\n";
1417 }
1418 break;
1419 }
1420}
1421
1431
1432void AttrTable::print(FILE *out, string pad, bool dereference)
1433{
1434 ostringstream oss;
1435 print(oss, pad, dereference);
1436 fwrite(oss.str().data(), 1, oss.str().length(), out);
1437
1438#if 0
1439 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1440 if ((*i)->is_alias) {
1441 if (dereference) {
1442 simple_print(out, pad, i, dereference);
1443 }
1444 else {
1445#if WWW_ENCODING
1446 fprintf(out, "%sAlias %s %s;\n",
1447 pad.c_str(),
1448 id2www(get_name(i)).c_str(),
1449 id2www((*i)->aliased_to).c_str());
1450#else
1451 fprintf(out, "%sAlias %s %s;\n",
1452 pad.c_str(), add_space_encoding(get_name(i)).c_str(), add_space_encoding((*i)->aliased_to).c_str());
1453
1454#endif
1455 }
1456 }
1457 else {
1458 simple_print(out, pad, i, dereference);
1459 }
1460 }
1461#endif
1462}
1463
1473
1474void AttrTable::print(ostream &out, string pad, bool dereference)
1475{
1476 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1477 if ((*i)->is_alias) {
1478 if (dereference) {
1479 simple_print(out, pad, i, dereference);
1480 }
1481 else {
1482#if WWW_ENCODING
1483 out << pad << "Alias " << id2www(get_name(i))
1484 << " " << id2www((*i)->aliased_to) << ";\n";
1485#else
1486 out << pad << "Alias " << add_space_encoding(get_name(i)) << " "
1487 << add_space_encoding((*i)->aliased_to) << ";\n";
1488#endif
1489 }
1490 }
1491 else {
1492 simple_print(out, pad, i, dereference);
1493 }
1494 }
1495}
1496
1502void AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/)
1503{
1504 XMLWriter xml(pad);
1505 print_xml_writer(xml);
1506 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1507
1508#if OLD_XML_MOETHODS
1509 ostringstream oss;
1510 print_xml(oss, pad);
1511 fwrite(oss.str().data(), 1, oss.str().length(), out);
1512#endif
1513
1514#if 0
1515 // Why this works: AttrTable is really a hacked class that used to
1516 // implement a single-level set of attributes. Containers
1517 // were added several years later by dropping in the 'entry' structure.
1518 // It's not a class in its own right; instead accessors from AttrTable
1519 // are used to access information from entry. So... the loop below
1520 // actually iterates over the entries of *this* (which is an instance of
1521 // AttrTable). A container is an entry whose sole value is an AttrTable
1522 // instance. 05/19/03 jhrg
1523 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1524 if ((*i)->is_alias) {
1525 fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n",
1526 pad.c_str(), id2xml(get_name(i)).c_str(),
1527 (*i)->aliased_to.c_str());
1528
1529 }
1530 else if (is_container(i)) {
1531 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
1532 pad.c_str(), id2xml(get_name(i)).c_str(),
1533 get_type(i).c_str());
1534
1535 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/);
1536
1537 fprintf(out, "%s</Attribute>\n", pad.c_str());
1538 }
1539 else {
1540 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
1541 pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str());
1542
1543 string value_pad = pad + " ";
1544 // Special handling for the OtherXML attribute type - don't escape
1545 // the XML and don't include the <value> element. Note that there
1546 // cannot be an vector of XML things as can be with the other types.
1547 if (get_attr_type(i) == Attr_other_xml) {
1548 if (get_attr_num(i) != 1)
1549 throw Error("OtherXML attributes cannot be vector-valued.");
1550 fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str());
1551 }
1552 else {
1553 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1554 fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(),
1555 id2xml(get_attr(i, j)).c_str());
1556 }
1557 }
1558 fprintf(out, "%s</Attribute>\n", pad.c_str());
1559 }
1560 }
1561#endif
1562}
1563
1567void AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/)
1568{
1569 XMLWriter xml(pad);
1570 print_xml_writer(xml);
1571 out << xml.get_doc();
1572
1573#if 0
1574 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1575 if ((*i)->is_alias) {
1576 out << pad << "<Alias name=\"" << id2xml(get_name(i))
1577 << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n";
1578
1579 }
1580 else if (is_container(i)) {
1581 out << pad << "<Attribute name=\"" << id2xml(get_name(i))
1582 << "\" type=\"" << get_type(i) << "\">\n";
1583
1584 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/);
1585
1586 out << pad << "</Attribute>\n";
1587 }
1588 else {
1589 out << pad << "<Attribute name=\"" << id2xml(get_name(i))
1590 << "\" type=\"" << get_type(i) << "\">\n";
1591
1592 string value_pad = pad + " ";
1593 if (get_attr_type(i) == Attr_other_xml) {
1594 if (get_attr_num(i) != 1)
1595 throw Error("OtherXML attributes cannot be vector-valued.");
1596 out << value_pad << get_attr(i, 0) << "\n";
1597 }
1598 else {
1599 string value_pad = pad + " ";
1600 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1601 out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n";
1602 }
1603 }
1604 out << pad << "</Attribute>\n";
1605 }
1606 }
1607#endif
1608}
1609
1615{
1616 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1617 if ((*i)->is_alias) {
1618 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Alias") < 0)
1619 throw InternalErr(__FILE__, __LINE__, "Could not write Alias element");
1620 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1621 (const xmlChar*) get_name(i).c_str()) < 0)
1622 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1623 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "Attribute",
1624 (const xmlChar*) (*i)->aliased_to.c_str()) < 0)
1625 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1626 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1627 throw InternalErr(__FILE__, __LINE__, "Could not end Alias element");
1628 }
1629 else if (is_container(i)) {
1630 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
1631 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
1632 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1633 (const xmlChar*) get_name(i).c_str()) < 0)
1634 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1635 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type",
1636 (const xmlChar*) get_type(i).c_str()) < 0)
1637 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1638
1640
1641 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1642 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
1643 }
1644 else {
1645 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
1646 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
1647 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1648 (const xmlChar*) get_name(i).c_str()) < 0)
1649 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1650 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type",
1651 (const xmlChar*) get_type(i).c_str()) < 0)
1652 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1653
1654 if (get_attr_type(i) == Attr_other_xml) {
1655 if (get_attr_num(i) != 1)
1656 throw Error("OtherXML attributes cannot be vector-valued.");
1657 // Replaced xmltextWriterWriteString with xmlTextWriterWriteRaw to keep the
1658 // libxml2 code from escaping the xml (which was breaking all of the inferencing
1659 // code. jhrg
1660 if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) get_attr(i, 0).c_str()) < 0)
1661 throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
1662 }
1663 // Need to escape special characters that xml doesn't allow. Note: the XML escaping is
1664 // not the same as the das string escaping. See escattr_xml in the escaping.cc for details.
1665 // KY 08-22-22
1666 else if (get_attr_type(i) == Attr_string || get_attr_type(i) == Attr_url) {
1667 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1668 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "value") < 0)
1669 throw InternalErr(__FILE__, __LINE__, "Could not write value element");
1670
1671 string s = ((*i)->is_utf8_str)?get_attr(i,j):escattr_xml(get_attr(i,j));
1672 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) s.c_str()) < 0)
1673 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
1674
1675 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1676 throw InternalErr(__FILE__, __LINE__, "Could not end value element");
1677 }
1678 }
1679 else {
1680 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1681 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "value") < 0)
1682 throw InternalErr(__FILE__, __LINE__, "Could not write value element");
1683
1684 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) get_attr(i, j).c_str()) < 0)
1685 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
1686
1687 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1688 throw InternalErr(__FILE__, __LINE__, "Could not end value element");
1689 }
1690 }
1691 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1692 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
1693 }
1694 }
1695}
1696
1702void
1707
1715void AttrTable::dump(ostream &strm) const
1716{
1717 strm << DapIndent::LMarg << "AttrTable::dump - (" << (void *) this << ")" << endl;
1718 DapIndent::Indent();
1719 strm << DapIndent::LMarg << "table name: " << d_name << endl;
1720 if (attr_map.size()) {
1721 strm << DapIndent::LMarg << "attributes: " << endl;
1722 DapIndent::Indent();
1723 Attr_citer i = attr_map.begin();
1724 Attr_citer ie = attr_map.end();
1725 for (; i != ie; ++i) {
1726 entry *e = (*i);
1727 string type = AttrType_to_String(e->type);
1728 if (e->is_alias) {
1729 strm << DapIndent::LMarg << "alias: " << e->name << " aliased to: " << e->aliased_to << endl;
1730 }
1731 else if (e->type == Attr_container) {
1732 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
1733 DapIndent::Indent();
1734 e->attributes->dump(strm);
1735 DapIndent::UnIndent();
1736 }
1737 else {
1738 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
1739 DapIndent::Indent();
1740 strm << DapIndent::LMarg;
1741 vector<string>::const_iterator iter = e->attr->begin();
1742 vector<string>::const_iterator last = e->attr->end() - 1;
1743 for (; iter != last; ++iter) {
1744 strm << (*iter) << ", ";
1745 }
1746 strm << (*(e->attr->end() - 1)) << endl;
1747 DapIndent::UnIndent();
1748 }
1749 }
1750 DapIndent::UnIndent();
1751 }
1752 else {
1753 strm << DapIndent::LMarg << "attributes: empty" << endl;
1754 }
1755 if (d_parent) {
1756 strm << DapIndent::LMarg << "parent table:" << d_name << ":" << (void *) d_parent << endl;
1757 }
1758 else {
1759 strm << DapIndent::LMarg << "parent table: none" << d_name << endl;
1760 }
1761 DapIndent::UnIndent();
1762}
1763
1764} // namespace libdap
1765
Contains the attributes for a dataset.
Definition AttrTable.h:154
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition AttrTable.cc:554
void simple_print(FILE *out, string pad, Attr_iter i, bool dereference)
virtual unsigned int get_attr_num(const string &name)
Get the number of attributes in this container.
Definition AttrTable.cc:778
bool has_dap4_types(const std::string &path, std::vector< std::string > &inventory) const
virtual bool attr_alias(const string &alias, AttrTable *at, const string &name)
Adds an alias to the set of attributes.
virtual bool is_container(Attr_iter iter)
Definition AttrTable.cc:890
virtual void find(const string &target, AttrTable **at, Attr_iter *iter)
Definition AttrTable.cc:625
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition AttrTable.cc:273
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition AttrTable.cc:751
void clone(const AttrTable &at)
Definition AttrTable.cc:188
virtual Attr_iter attr_end()
Definition AttrTable.cc:863
virtual void print_xml(FILE *out, string pad=" ", bool constrained=false)
virtual string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition AttrTable.cc:757
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition AttrTable.cc:797
virtual void add_value_alias(AttrTable *at, const string &name, const string &source)
Add an alias for an attribute.
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition AttrTable.cc:335
virtual Attr_iter attr_begin()
Definition AttrTable.cc:855
virtual Attr_iter get_attr_iter(int i)
Definition AttrTable.cc:876
void print_dap4(XMLWriter &xml)
virtual void del_attr(const string &name, int i=-1)
Deletes an attribute.
Definition AttrTable.cc:819
virtual string get_name() const
Get the name of this attribute table.
Definition AttrTable.cc:266
virtual void erase()
Erase the attribute table.
void print_xml_writer(XMLWriter &xml)
virtual Attr_iter del_attr_table(Attr_iter iter)
Definition AttrTable.cc:925
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
virtual void add_container_alias(const string &name, AttrTable *src)
Add an alias to a container held by this attribute table.
virtual unsigned int get_size() const
Get the number of entries in this attribute table.
Definition AttrTable.cc:259
virtual void dump(ostream &strm) const
dumps information about this object
virtual AttrTable * find_container(const string &target)
Find an attribute with a given name.
Definition AttrTable.cc:710
Attr_iter simple_find(const string &target)
Definition AttrTable.cc:685
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition AttrTable.cc:765
virtual AttrTable * recurrsive_find(const string &target, Attr_iter *location)
Definition AttrTable.cc:657
libdap base object for common functionality of libdap objects
Definition DapObj.h:51
A class for error processing.
Definition Error.h:94
A class for software fault reporting.
Definition InternalErr.h:65
STL iterator class.
STL iterator class.
top level DAP object to house generic methods
Definition AISConnect.cc:30
string escattr(string s)
Definition escaping.cc:368
string escattr_xml(string s)
Definition escaping.cc:402
string www2id(const string &in, const string &escape, const string &except)
Definition escaping.cc:220
string id2xml(string in, const string &not_allowed)
Definition escaping.cc:272
string add_space_encoding(const string &s)
Definition AttrTable.cc:78
void downcase(string &s)
Definition util.cc:566
string AttrType_to_String(const AttrType at)
Definition AttrTable.cc:97
string escape_double_quotes(string source)
Definition escaping.cc:499
string remove_space_encoding(const string &s)
Definition AttrTable.cc:61
bool is_quoted(const string &s)
Definition util.cc:577
string id2www(string in, const string &allowable)
Definition escaping.cc:153