libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
AttrTable.cc
Go to the documentation of this file.
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 "DapIndent.h"
41#include "escaping.h"
42#include "util.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::endl;
55using std::string;
56using std::vector;
57
58namespace libdap {
59
61string remove_space_encoding(const string &s) {
62 string::size_type pos = s.find("%20");
63 if (pos != string::npos) {
64 string n = s;
65 do {
66 n.replace(pos, 3, " ");
67 pos = n.find("%20");
68 } while (pos != string::npos);
69 return n;
70 } else {
71 return s;
72 }
73}
74
76string add_space_encoding(const string &s) {
77 string::size_type pos = s.find(" ");
78 if (pos != string::npos) {
79 string n = s;
80 do {
81 n.replace(pos, 1, "%20");
82 pos = n.find(" ");
83 } while (pos != string::npos);
84 return n;
85 } else {
86 return s;
87 }
88}
89
93string AttrType_to_String(const AttrType at) {
94 switch (at) {
95 case Attr_container:
96 return "Container";
97 case Attr_byte:
98 return "Byte";
99 case Attr_int16:
100 return "Int16";
101 case Attr_uint16:
102 return "UInt16";
103 case Attr_int32:
104 return "Int32";
105 case Attr_uint32:
106 return "UInt32";
107 case Attr_float32:
108 return "Float32";
109 case Attr_float64:
110 return "Float64";
111 case Attr_string:
112 return "String";
113 case Attr_url:
114 return "Url";
115 case Attr_other_xml:
116 return "OtherXML";
117 //
118 // Added for DAP4
119 case Attr_int8:
120 return "Int8";
121 case Attr_uint8:
122 return "UInt8";
123 case Attr_int64:
124 return "Int64";
125 case Attr_uint64:
126 return "UInt64";
127 case Attr_enum:
128 return "Enumeration";
129 case Attr_opaque:
130 return "Opaque";
131 default:
132 return "";
133 }
134}
135
136AttrType String_to_AttrType(const string &s) {
137 string s2 = s;
138 downcase(s2);
139
140 if (s2 == "container")
141 return Attr_container;
142 else if (s2 == "byte")
143 return Attr_byte;
144 else if (s2 == "int16")
145 return Attr_int16;
146 else if (s2 == "uint16")
147 return Attr_uint16;
148 else if (s2 == "int32")
149 return Attr_int32;
150 else if (s2 == "uint32")
151 return Attr_uint32;
152 else if (s2 == "float32")
153 return Attr_float32;
154 else if (s2 == "float64")
155 return Attr_float64;
156 else if (s2 == "string")
157 return Attr_string;
158 else if (s2 == "url")
159 return Attr_url;
160 else if (s2 == "otherxml")
161 return Attr_other_xml;
162 //
163 // Added for DAP4
164 else if (s2 == "int8")
165 return Attr_int8;
166 else if (s2 == "uint8")
167 return Attr_uint8;
168 else if (s2 == "int64")
169 return Attr_int64;
170 else if (s2 == "uint64")
171 return Attr_uint64;
172 else if (s2 == "enumeration")
173 return Attr_enum;
174 else if (s2 == "opaque")
175 return Attr_opaque;
176 else
177 return Attr_unknown;
178}
179
183 d_name = at.d_name;
184 d_is_global_attribute = at.d_is_global_attribute;
185
186 // Set the parent to null (no parent, not in container)
187 // since using at.d_parent is semantically incorrect
188 // and potentially dangerous.
189 d_parent = 0;
190
191 Attr_citer i = at.attr_map.begin();
192 Attr_citer ie = at.attr_map.end();
193 for (; i != ie; ++i) {
194 // this deep-copies containers recursively
195 entry *e = new entry(*(*i));
196 attr_map.push_back(e);
197
198 // If the entry being added was a container,
199 // set its parent to this to maintain invariant.
200 if (e->type == Attr_container) {
201 assert(e->attributes);
202 e->attributes->d_parent = this;
203 }
204 }
205}
206
208
210AttrTable::AttrTable() : DapObj(), d_name(""), d_parent(0), attr_map(), d_is_global_attribute(true) {}
211
213
214// Private
215void AttrTable::delete_attr_table() {
216 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
217 delete *i;
218 }
219 attr_map.clear();
220}
221
222AttrTable::~AttrTable() { delete_attr_table(); }
223
225 if (this != &rhs) {
226 delete_attr_table();
227 clone(rhs);
228 }
229
230 return *this;
231}
232
233
239unsigned int AttrTable::get_size() const { return attr_map.size(); }
240
243string AttrTable::get_name() const { return d_name; }
244
247void AttrTable::set_name(const string &n) {
248#if WWW_ENCODING
249 d_name = www2id(n);
250#else
251 d_name = remove_space_encoding(n);
252#endif
253}
254
255#if 0
256// This was taken from das.y and could be used here to make the 'dods_errors'
257// attribute container like the parser used to. Then again, maybe this feature
258// was just BS. jhrg (ticket 1469)
259static void add_bad_attribute(AttrTable *attr, const string &type, const string &name, const string &value,
260 const string &msg) {
261 // First, if this bad value is already in a *_dods_errors container,
262 // then just add it. This can happen when the server side processes a DAS
263 // and then hands it off to a client which does the same.
264 // Make a new container. Call it <attr's name>_errors. If that container
265 // already exists, use it.
266 // Add the attribute.
267 // Add the error string to an attribute in the container called
268 // `<name_explanation.'.
269
270 if (attr->get_name().find("_dods_errors") != string::npos) {
271 attr->append_attr(name, type, value);
272 }
273 else {
274 // I think _dods_errors should be _dap_error. jhrg 11/16/11
275 string error_cont_name = attr->get_name() + "_dods_errors";
276 AttrTable *error_cont = attr->get_attr_table(error_cont_name);
277 if (!error_cont)
278 error_cont = attr->append_container(error_cont_name);
279
280 error_cont->append_attr(name, type, value);
281
282#ifndef ATTR_STRING_QUOTE_FIX
283 error_cont->append_attr(name + "_dap_explanation", "String", "\"" + msg + "\"");
284#else
285 error_cont->append_attr(name + "_dap_explanation", "String", msg);
286#endif
287 }
288}
289#endif
290
308unsigned int AttrTable::append_attr(const string &name, const string &type, const string &value) {
309 DBG(cerr << "Entering AttrTable::append_attr" << endl);
310#if WWW_ENCODING
311 string lname = www2id(name);
312#else
313 string lname = remove_space_encoding(name);
314#endif
315
316 Attr_iter iter = simple_find(lname);
317
318 // If the types don't match OR this attribute is a container, calling
319 // this mfunc is an error!
320 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
321 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
322 if (iter != attr_map.end() && (get_type(iter) == "Container"))
323 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
324
325 if (iter != attr_map.end()) { // Must be a new attribute value; add it.
326 (*iter)->attr->push_back(value);
327 return (*iter)->attr->size();
328 } else { // Must be a completely new attribute; add it
329 entry *e = new entry;
330
331 e->name = lname;
332 e->is_alias = false;
333 e->type = String_to_AttrType(type); // Record type using standard names.
334 e->attr = new vector<string>;
335 e->attr->push_back(value);
336
337 attr_map.push_back(e);
338
339 return e->attr->size(); // return the length of the attr vector
340 }
341}
342
360
361unsigned int AttrTable::append_attr(const string &name, const string &type, vector<string> *values) {
362 DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl);
363#if WWW_ENCODING
364 string lname = www2id(name);
365#else
366 string lname = remove_space_encoding(name);
367#endif
368 Attr_iter iter = simple_find(lname);
369
370 // If the types don't match OR this attribute is a container, calling
371 // this mfunc is an error!
372 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
373 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
374 if (iter != attr_map.end() && (get_type(iter) == "Container"))
375 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
376
377 if (iter != attr_map.end()) { // Must be new attribute values; add.
378 vector<string>::iterator i = values->begin();
379 while (i != values->end())
380 (*iter)->attr->push_back(*i++);
381
382 return (*iter)->attr->size();
383 } else { // Must be a completely new attribute; add it
384 entry *e = new entry;
385
386 e->name = lname;
387 e->is_alias = false;
388 e->type = String_to_AttrType(type); // Record type using standard names.
389 e->attr = new vector<string>(*values);
390
391 attr_map.push_back(e);
392
393 return e->attr->size(); // return the length of the attr vector
394 }
395}
396
415unsigned int AttrTable::append_attr(const string &name, const string &type, const string &value, bool is_utf8_str) {
416 DBG(cerr << "Entering AttrTable::append_attr" << endl);
417#if WWW_ENCODING
418 string lname = www2id(name);
419#else
420 string lname = remove_space_encoding(name);
421#endif
422
423 Attr_iter iter = simple_find(lname);
424
425 // If the types don't match OR this attribute is a container, calling
426 // this mfunc is an error!
427 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
428 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
429 if (iter != attr_map.end() && (get_type(iter) == "Container"))
430 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
431
432 if (iter != attr_map.end()) { // Must be a new attribute value; add it.
433 (*iter)->attr->push_back(value);
434 (*iter)->is_utf8_str = is_utf8_str;
435 return (*iter)->attr->size();
436 } else { // Must be a completely new attribute; add it
437 entry *e = new entry;
438
439 e->name = lname;
440 e->is_alias = false;
441 e->type = String_to_AttrType(type); // Record type using standard names.
442 e->is_utf8_str = is_utf8_str;
443 e->attr = new vector<string>;
444 e->attr->push_back(value);
445
446 attr_map.push_back(e);
447
448 return e->attr->size(); // return the length of the attr vector
449 }
450}
451
470
471unsigned int AttrTable::append_attr(const string &name, const string &type, vector<string> *values, bool is_utf8_str) {
472 DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl);
473#if WWW_ENCODING
474 string lname = www2id(name);
475#else
476 string lname = remove_space_encoding(name);
477#endif
478 Attr_iter iter = simple_find(lname);
479
480 // If the types don't match OR this attribute is a container, calling
481 // this mfunc is an error!
482 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
483 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
484 if (iter != attr_map.end() && (get_type(iter) == "Container"))
485 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
486
487 if (iter != attr_map.end()) { // Must be new attribute values; add.
488 vector<string>::iterator i = values->begin();
489 while (i != values->end())
490 (*iter)->attr->push_back(*i++);
491 (*iter)->is_utf8_str = is_utf8_str;
492 return (*iter)->attr->size();
493 } else { // Must be a completely new attribute; add it
494 entry *e = new entry;
495
496 e->name = lname;
497 e->is_alias = false;
498 e->type = String_to_AttrType(type); // Record type using standard names.
499 e->is_utf8_str = is_utf8_str;
500 e->attr = new vector<string>(*values);
501
502 attr_map.push_back(e);
503
504 return e->attr->size(); // return the length of the attr vector
505 }
506}
507
516
518 AttrTable *new_at = new AttrTable;
519 AttrTable *ret = NULL;
520 try {
521 ret = append_container(new_at, name);
522 } catch (Error &e) {
523 // an error occurred, attribute with that name already exists
524 delete new_at;
525 new_at = 0;
526 throw;
527 }
528 return ret;
529}
530
546#if WWW_ENCODING
547 string lname = www2id(name);
548#else
549 string lname = remove_space_encoding(name);
550#endif
551
552 if (simple_find(name) != attr_end())
553 throw Error("There already exists a container called '" + name + "' in this attribute table (" +
554 at->get_name() + "). (1)");
555
556 DBG(cerr << "Setting appended attribute container name to: " << lname << endl);
557 at->set_name(lname);
558
559 entry *e = new entry;
560 e->name = lname;
561 e->is_alias = false;
562 e->type = Attr_container;
563 e->attributes = at;
564
565 attr_map.push_back(e);
566
567 at->d_parent = this;
568
569 return e->attributes;
570}
571
586void AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter) {
587 string::size_type dotpos = target.rfind('.');
588 if (dotpos != string::npos) {
589 string container = target.substr(0, dotpos);
590 string field = target.substr(dotpos + 1);
591
592 *at = find_container(container);
593 if (*at) {
594 *iter = (*at)->simple_find(field);
595 } else {
596 *iter = attr_map.end();
597 }
598 } else {
599 *at = recurrsive_find(target, iter);
600 }
601}
602
614AttrTable *AttrTable::recurrsive_find(const string &target, Attr_iter *location) {
615 Attr_iter i = attr_begin();
616 while (i != attr_end()) {
617 if (target == (*i)->name) {
618 *location = i;
619 return this;
620 } else if ((*i)->type == Attr_container) {
621 AttrTable *at = (*i)->attributes->recurrsive_find(target, location);
622 if (at)
623 return at;
624 }
625
626 ++i;
627 }
628
629 *location = i;
630 return 0;
631}
632
633// Made public for callers that want non-recursive find. [mjohnson 6 oct 09]
641 Attr_iter i;
642 for (i = attr_map.begin(); i != attr_map.end(); ++i) {
643 if (target == (*i)->name) {
644 break;
645 }
646 }
647 return i;
648}
649
663AttrTable *AttrTable::find_container(const string &target) {
664 string::size_type dotpos = target.find('.');
665 if (dotpos != string::npos) {
666 string container = target.substr(0, dotpos);
667 string field = target.substr(dotpos + 1);
668
669 AttrTable *at = simple_find_container(container);
670 return (at) ? at->find_container(field) : 0;
671 } else {
672 return simple_find_container(target);
673 }
674}
675
676// Made public for callers that want non-recursive find. [mjohnson 6 oct 09]
678 if (get_name() == target)
679 return this;
680
681 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
682 if (is_container(i) && target == (*i)->name) {
683 return (*i)->attributes;
684 }
685 }
686
687 return 0;
688}
689
697
699AttrTable *AttrTable::get_attr_table(const string &name) { return find_container(name); }
700
702string AttrTable::get_type(const string &name) {
703 Attr_iter p = simple_find(name);
704 return (p != attr_map.end()) ? get_type(p) : (string) "";
705}
706
710 Attr_iter p = simple_find(name);
711 return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown;
712}
713
721unsigned int AttrTable::get_attr_num(const string &name) {
722 Attr_iter iter = simple_find(name);
723 return (iter != attr_map.end()) ? get_attr_num(iter) : 0;
724}
725
738vector<string> *AttrTable::get_attr_vector(const string &name) {
739 Attr_iter p = simple_find(name);
740 return (p != attr_map.end()) ? get_attr_vector(p) : 0;
741}
742
759void AttrTable::del_attr(const string &name, int i) {
760#if WWW_ENCODING
761 string lname = www2id(name);
762#else
763 string lname = remove_space_encoding(name);
764#endif
765
766 Attr_iter iter = simple_find(lname);
767 if (iter != attr_map.end()) {
768 if (i == -1) { // Delete the whole attribute
769 entry *e = *iter;
770 attr_map.erase(iter);
771 delete e;
772 e = 0;
773 } else { // Delete one element from attribute array
774 // Don't try to delete elements from the vector of values if the
775 // map is a container!
776 if ((*iter)->type == Attr_container)
777 return;
778
779 vector<string> *sxp = (*iter)->attr;
780
781 assert(i >= 0 && i < (int)sxp->size());
782 sxp->erase(sxp->begin() + i); // rm the element
783 }
784 }
785}
786
788
791
793AttrTable::Attr_iter AttrTable::attr_begin() { return attr_map.begin(); }
794
798AttrTable::Attr_iter AttrTable::attr_end() { return attr_map.end(); }
799
808AttrTable::Attr_iter AttrTable::get_attr_iter(int i) { return attr_map.begin() + i; }
809
812 assert(iter != attr_map.end());
813
814 return (*iter)->name;
815}
816
818bool AttrTable::is_container(Attr_iter i) { return (*i)->type == Attr_container; }
819
826 assert(iter != attr_map.end());
827 return (*iter)->type == Attr_container ? (*iter)->attributes : 0;
828}
829
849 if ((*iter)->type != Attr_container)
850 return ++iter;
851
852 // the caller intends to delete/reuse the contained AttrTable,
853 // so zero it out so it doesn't get deleted before we delete the entry
854 // [mjohnson]
855 struct entry *e = *iter;
856 // container no longer has a parent.
857 if (e->attributes) {
858 e->attributes->d_parent = 0;
859
860#if NEW_DEL_ATTR_TABLE_BEHAVIOR
861 delete e->attributes;
862#endif
863 e->attributes = 0;
864 }
865
866 delete e;
867
868 return attr_map.erase(iter);
869}
870
875 assert(iter != attr_map.end());
876 return AttrType_to_String((*iter)->type);
877}
878
882AttrType AttrTable::get_attr_type(Attr_iter iter) { return (*iter)->type; }
883
892 assert(iter != attr_map.end());
893 return ((*iter)->type == Attr_container) ? (*iter)->attributes->get_size() : (*iter)->attr->size();
894}
895
912string AttrTable::get_attr(Attr_iter iter, unsigned int i) {
913 assert(iter != attr_map.end());
914
915 return (*iter)->type == Attr_container ? (string) "None" : (*(*iter)->attr)[i];
916}
917
918string AttrTable::get_attr(const string &name, unsigned int i) {
919 Attr_iter p = simple_find(name);
920 return (p != attr_map.end()) ? get_attr(p, i) : (string) "";
921}
922
935 assert(iter != attr_map.end());
936 return (*iter)->type != Attr_container ? (*iter)->attr : 0;
937}
938
940 assert(iter != attr_map.end());
941 if ((*iter)->type == Attr_container)
942 return (*iter)->attributes->is_global_attribute();
943 else
944 return (*iter)->is_global;
945}
946
948 assert(iter != attr_map.end());
949 if ((*iter)->type == Attr_container)
950 (*iter)->attributes->set_is_global_attribute(ga);
951 else
952 (*iter)->is_global = ga;
953}
954
956
957// Alias an attribute table. The alias should be added to this object.
963void AttrTable::add_container_alias(const string &name, AttrTable *src) {
964#if WWW_ENCODING
965 string lname = www2id(name);
966#else
967 string lname = remove_space_encoding(name);
968#endif
969
970 if (simple_find(lname) != attr_end())
971 throw Error(string("There already exists a container called `") + name +
972 string("in this attribute table. (2)"));
973
974 entry *e = new entry;
975 e->name = lname;
976 e->is_alias = true;
977 e->aliased_to = src->get_name();
978 e->type = Attr_container;
979
980 e->attributes = src;
981
982 attr_map.push_back(e);
983}
984
997void AttrTable::add_value_alias(AttrTable *das, const string &name, const string &source) {
998#if WWW_ENCODING
999 string lname = www2id(name);
1000#else
1001 string lname = remove_space_encoding(name);
1002#endif
1003
1004#if WWW_ENCODING
1005 string lsource = www2id(source);
1006#else
1007 string lsource = remove_space_encoding(source);
1008#endif
1009
1010 // find the container that holds source and its (sources's) iterator
1011 // within that container. Search at the uppermost level of the attribute
1012 // object to find values defined `above' the current container.
1013 AttrTable *at;
1014 Attr_iter iter;
1015 das->find(lsource, &at, &iter);
1016
1017 // If source is not found by looking at the topmost level, look in the
1018 // current table (i.e., alias z x where x is in the current container
1019 // won't be found by looking for `x' at the top level). See test case 26
1020 // in das-testsuite.
1021 if (!at || (iter == at->attr_end()) || !*iter) {
1022 find(lsource, &at, &iter);
1023 if (!at || (iter == at->attr_end()) || !*iter)
1024 throw Error(string("Could not find the attribute `") + source + string("' in the attribute object."));
1025 }
1026
1027 // If we've got a value to alias and it's being added at the top level of
1028 // the DAS, that's an error.
1029 if (at && !at->is_container(iter) && this == das)
1030 throw Error(string("A value cannot be aliased to the top level of the DAS;\nOnly containers may be present at "
1031 "that level of the DAS."));
1032
1033 if (simple_find(lname) != attr_end())
1034 throw Error(string("There already exists a container called `") + name +
1035 string("in this attribute table. (3)"));
1036
1037 entry *e = new entry;
1038 e->name = lname;
1039 e->is_alias = true;
1040 e->aliased_to = lsource;
1041 e->type = get_attr_type(iter);
1042 if (at && e->type == Attr_container)
1043 e->attributes = at->get_attr_table(iter);
1044 else
1045 e->attr = (*iter)->attr;
1046
1047 attr_map.push_back(e);
1048}
1049
1050// Deprecated
1069bool AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name) {
1070 add_value_alias(at, alias, name);
1071 return true;
1072}
1073
1081bool AttrTable::attr_alias(const string &alias, const string &name) { return attr_alias(alias, this, name); }
1082
1089bool AttrTable::has_dap4_types(const std::string &path, std::vector<std::string> &inventory) const {
1090 bool has_d4_attr = false;
1091 for (auto attr : attr_map) {
1092 string attr_fqn = path + "@" + attr->name;
1093 bool isa_d4_attr = attr->is_dap4_type(attr_fqn, inventory);
1094 if (isa_d4_attr) {
1095 inventory.emplace_back(AttrType_to_String(attr->type) + " " + attr_fqn);
1096 }
1097 has_d4_attr |= isa_d4_attr;
1098 }
1099 return has_d4_attr;
1100}
1101
1106 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1107 delete *i;
1108 *i = 0;
1109 }
1110
1111 attr_map.erase(attr_map.begin(), attr_map.end());
1112
1113 d_name = "";
1114}
1115
1116const string double_quote = "\"";
1117
1118// This is here as a result of the problem described in ticket #1163 where
1119// the data handlers are adding quotes to string attributes so the DAS will
1120// be printed correctly. But that has the affect of adding the quotes to the
1121// attribute's _value_ not just it's print representation. As part of the fix
1122// I made the code here add the quotes if the handlers are fixed (but not if
1123// handlers are still adding them). The other part of 1163 is to fix all of
1124// the handlers... What this fix means is that attributes whose values really
1125// do contain bracketing quotes might be misunderstood, since we're assuming
1126// those quotes were added by the handlers as a hack to get the output
1127// formatting correct for the DAS. jhrg 7/30/08
1128
1129static void write_string_attribute_for_das(ostream &out, const string &value, const string &term, bool is_utf8_str) {
1130
1131 string esc_value = is_utf8_str ? value : escattr(value);
1132#if 0
1133 string esc_value = escattr(value);
1134#endif
1135
1136 // The value is already escaped so the following check is not necessary. KY 2022-08-22
1137#if 0
1138 if (is_quoted(esc_value))
1139 out << esc_value << term;
1140 else
1141#endif
1142 out << double_quote << esc_value << double_quote << term;
1143}
1144
1145#if 0
1146static void
1147write_string_attribute_for_das(FILE *out, const string &value, const string &term)
1148{
1149 if (is_quoted(value))
1150 fprintf(out, "%s%s", value.c_str(), term.c_str());
1151 else
1152 fprintf(out, "\"%s\"%s", value.c_str(), term.c_str());
1153}
1154#endif
1155
1156// Special treatment for XML: Make sure to escape double quotes when XML is
1157// printed in a DAS.
1158static void write_xml_attribute_for_das(ostream &out, const string &value, const string &term) {
1159 if (is_quoted(value))
1160 out << escape_double_quotes(value) << term;
1161 else
1162 out << double_quote << escape_double_quotes(value) << double_quote << term;
1163}
1164
1165#if 0
1166static void
1167write_xml_attribute_for_das(FILE *out, const string &value, const string &term)
1168{
1169 if (is_quoted(value))
1170 fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str());
1171 else
1172 fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str());
1173}
1174#endif
1175
1178void AttrTable::simple_print(FILE *out, string pad, Attr_iter i, bool dereference) {
1179 ostringstream oss;
1180 simple_print(oss, pad, i, dereference);
1181 fwrite(oss.str().data(), 1, oss.str().length(), out);
1182
1183#if 0
1184 switch ((*i)->type) {
1185 case Attr_container:
1186#if WWW_ENCODING
1187 fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str());
1188#else
1189 fprintf(out, "%s%s {\n", pad.c_str(), get_name(i).c_str());
1190#endif
1191 (*i)->attributes->print(out, pad + " ", dereference);
1192
1193 fprintf(out, "%s}\n", pad.c_str());
1194 break;
1195
1196 case Attr_string: {
1197#if WWW_ENCODING
1198 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1199#else
1200 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1201#endif
1202 vector<string> *sxp = (*i)->attr;
1203 vector<string>::iterator last = sxp->end() - 1;
1204 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1205 write_string_attribute_for_das(out, *i, ", ");
1206 }
1207 write_string_attribute_for_das(out, *last, ";\n");
1208 }
1209 break;
1210
1211 case Attr_other_xml: {
1212#if WWW_ENCODING
1213 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1214#else
1215 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1216#endif
1217 vector<string> *sxp = (*i)->attr;
1218 vector<string>::iterator last = sxp->end() - 1;
1219 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1220 write_xml_attribute_for_das(out, *i, ", ");
1221 }
1222 write_xml_attribute_for_das(out, *last, ";\n");
1223 }
1224 break;
1225
1226 default: {
1227#if WWW_ENCODING
1228 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1229#else
1230 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1231#endif
1232
1233 vector<string> *sxp = (*i)->attr;
1234 vector<string>::iterator last = sxp->end() - 1;
1235 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1236 fprintf(out, "%s%s", (*i).c_str(), ", ");
1237 }
1238 fprintf(out, "%s%s", (*last).c_str(), ";\n");
1239 }
1240 break;
1241 }
1242#endif
1243}
1244
1247void AttrTable::simple_print(ostream &out, string pad, Attr_iter i, bool dereference) {
1248 switch ((*i)->type) {
1249 case Attr_container:
1250#if WWW_ENCODING
1251 out << pad << id2www(get_name(i)) << " {\n";
1252#else
1253 out << pad << add_space_encoding(get_name(i)) << " {\n";
1254#endif
1255 (*i)->attributes->print(out, pad + " ", dereference);
1256 out << pad << "}\n";
1257 break;
1258
1259 case Attr_string: {
1260#if WWW_ENCODING
1261 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1262#else
1263 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1264#endif
1265 vector<string> *sxp = (*i)->attr;
1266
1267 vector<string>::iterator last = sxp->end() - 1;
1268 for (vector<string>::iterator i_s = sxp->begin(); i_s != last; ++i_s) {
1269 write_string_attribute_for_das(out, *i_s, ", ", (*i)->is_utf8_str);
1270 }
1271 write_string_attribute_for_das(out, *last, ";\n", (*i)->is_utf8_str);
1272
1273 // The following code is intended to replace the code above.
1274 // However, it causes the obscure test failure at HDF5 handler's t_big_str.h5 DAS test.
1275 // it also causes the 17th etc NcML tests failed.
1276 // Leave here and may check this later. KY 2022-09-22
1277#if 0
1278 for (const auto &attr:(*sxp)) {
1279 if (attr != (*sxp).back())
1280 write_string_attribute_for_das(out, attr, ", ",(*i)->is_utf8_str);
1281 else
1282 write_string_attribute_for_das(out, attr, ";\n",(*i)->is_utf8_str);
1283 }
1284#endif
1285 } break;
1286
1287 case Attr_other_xml: {
1288#if WWW_ENCODING
1289 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1290#else
1291 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1292#endif
1293 vector<string> *sxp = (*i)->attr;
1294 vector<string>::iterator last = sxp->end() - 1;
1295 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1296 write_xml_attribute_for_das(out, *i, ", ");
1297 }
1298 write_xml_attribute_for_das(out, *last, ";\n");
1299 } break;
1300
1301 default: {
1302#if WWW_ENCODING
1303 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1304#else
1305 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1306#endif
1307 vector<string> *sxp = (*i)->attr;
1308 vector<string>::iterator last = sxp->end() - 1;
1309 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1310 out << *i << ", ";
1311 }
1312 out << *last << ";\n";
1313 } break;
1314 }
1315}
1316
1326
1327void AttrTable::print(FILE *out, string pad, bool dereference) {
1328 ostringstream oss;
1329 print(oss, pad, dereference);
1330 fwrite(oss.str().data(), 1, oss.str().length(), out);
1331
1332#if 0
1333 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1334 if ((*i)->is_alias) {
1335 if (dereference) {
1336 simple_print(out, pad, i, dereference);
1337 }
1338 else {
1339#if WWW_ENCODING
1340 fprintf(out, "%sAlias %s %s;\n",
1341 pad.c_str(),
1342 id2www(get_name(i)).c_str(),
1343 id2www((*i)->aliased_to).c_str());
1344#else
1345 fprintf(out, "%sAlias %s %s;\n",
1346 pad.c_str(), add_space_encoding(get_name(i)).c_str(), add_space_encoding((*i)->aliased_to).c_str());
1347
1348#endif
1349 }
1350 }
1351 else {
1352 simple_print(out, pad, i, dereference);
1353 }
1354 }
1355#endif
1356}
1357
1367
1368void AttrTable::print(ostream &out, string pad, bool dereference) {
1369 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1370 if ((*i)->is_alias) {
1371 if (dereference) {
1372 simple_print(out, pad, i, dereference);
1373 } else {
1374#if WWW_ENCODING
1375 out << pad << "Alias " << id2www(get_name(i)) << " " << id2www((*i)->aliased_to) << ";\n";
1376#else
1377 out << pad << "Alias " << add_space_encoding(get_name(i)) << " " << add_space_encoding((*i)->aliased_to)
1378 << ";\n";
1379#endif
1380 }
1381 } else {
1382 simple_print(out, pad, i, dereference);
1383 }
1384 }
1385}
1386
1392void AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/) {
1393 XMLWriter xml(pad);
1394 print_xml_writer(xml);
1395 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1396
1397#if OLD_XML_MOETHODS
1398 ostringstream oss;
1399 print_xml(oss, pad);
1400 fwrite(oss.str().data(), 1, oss.str().length(), out);
1401#endif
1402
1403#if 0
1404 // Why this works: AttrTable is really a hacked class that used to
1405 // implement a single-level set of attributes. Containers
1406 // were added several years later by dropping in the 'entry' structure.
1407 // It's not a class in its own right; instead accessors from AttrTable
1408 // are used to access information from entry. So... the loop below
1409 // actually iterates over the entries of *this* (which is an instance of
1410 // AttrTable). A container is an entry whose sole value is an AttrTable
1411 // instance. 05/19/03 jhrg
1412 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1413 if ((*i)->is_alias) {
1414 fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n",
1415 pad.c_str(), id2xml(get_name(i)).c_str(),
1416 (*i)->aliased_to.c_str());
1417
1418 }
1419 else if (is_container(i)) {
1420 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
1421 pad.c_str(), id2xml(get_name(i)).c_str(),
1422 get_type(i).c_str());
1423
1424 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/);
1425
1426 fprintf(out, "%s</Attribute>\n", pad.c_str());
1427 }
1428 else {
1429 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
1430 pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str());
1431
1432 string value_pad = pad + " ";
1433 // Special handling for the OtherXML attribute type - don't escape
1434 // the XML and don't include the <value> element. Note that there
1435 // cannot be an vector of XML things as can be with the other types.
1436 if (get_attr_type(i) == Attr_other_xml) {
1437 if (get_attr_num(i) != 1)
1438 throw Error("OtherXML attributes cannot be vector-valued.");
1439 fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str());
1440 }
1441 else {
1442 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1443 fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(),
1444 id2xml(get_attr(i, j)).c_str());
1445 }
1446 }
1447 fprintf(out, "%s</Attribute>\n", pad.c_str());
1448 }
1449 }
1450#endif
1451}
1452
1456void AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/) {
1457 XMLWriter xml(pad);
1458 print_xml_writer(xml);
1459 out << xml.get_doc();
1460
1461#if 0
1462 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1463 if ((*i)->is_alias) {
1464 out << pad << "<Alias name=\"" << id2xml(get_name(i))
1465 << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n";
1466
1467 }
1468 else if (is_container(i)) {
1469 out << pad << "<Attribute name=\"" << id2xml(get_name(i))
1470 << "\" type=\"" << get_type(i) << "\">\n";
1471
1472 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/);
1473
1474 out << pad << "</Attribute>\n";
1475 }
1476 else {
1477 out << pad << "<Attribute name=\"" << id2xml(get_name(i))
1478 << "\" type=\"" << get_type(i) << "\">\n";
1479
1480 string value_pad = pad + " ";
1481 if (get_attr_type(i) == Attr_other_xml) {
1482 if (get_attr_num(i) != 1)
1483 throw Error("OtherXML attributes cannot be vector-valued.");
1484 out << value_pad << get_attr(i, 0) << "\n";
1485 }
1486 else {
1487 string value_pad = pad + " ";
1488 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1489 out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n";
1490 }
1491 }
1492 out << pad << "</Attribute>\n";
1493 }
1494 }
1495#endif
1496}
1497
1503 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1504 if ((*i)->is_alias) {
1505 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Alias") < 0)
1506 throw InternalErr(__FILE__, __LINE__, "Could not write Alias element");
1507 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"name",
1508 (const xmlChar *)get_name(i).c_str()) < 0)
1509 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1510 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"Attribute",
1511 (const xmlChar *)(*i)->aliased_to.c_str()) < 0)
1512 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1513 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1514 throw InternalErr(__FILE__, __LINE__, "Could not end Alias element");
1515 } else if (is_container(i)) {
1516 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Attribute") < 0)
1517 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
1518 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"name",
1519 (const xmlChar *)get_name(i).c_str()) < 0)
1520 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1521 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"type",
1522 (const xmlChar *)get_type(i).c_str()) < 0)
1523 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1524
1526
1527 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1528 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
1529 } else {
1530 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Attribute") < 0)
1531 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
1532 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"name",
1533 (const xmlChar *)get_name(i).c_str()) < 0)
1534 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1535 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"type",
1536 (const xmlChar *)get_type(i).c_str()) < 0)
1537 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1538
1539 if (get_attr_type(i) == Attr_other_xml) {
1540 if (get_attr_num(i) != 1)
1541 throw Error("OtherXML attributes cannot be vector-valued.");
1542 // Replaced xmltextWriterWriteString with xmlTextWriterWriteRaw to keep the
1543 // libxml2 code from escaping the xml (which was breaking all of the inferencing
1544 // code. jhrg
1545 if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar *)get_attr(i, 0).c_str()) < 0)
1546 throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
1547 }
1548 // Need to escape special characters that xml doesn't allow. Note: the XML escaping is
1549 // not the same as the das string escaping. See escattr_xml in the escaping.cc for details.
1550 // KY 08-22-22
1551 else if (get_attr_type(i) == Attr_string || get_attr_type(i) == Attr_url) {
1552 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1553 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"value") < 0)
1554 throw InternalErr(__FILE__, __LINE__, "Could not write value element");
1555
1556 string s = ((*i)->is_utf8_str) ? get_attr(i, j) : escattr_xml(get_attr(i, j));
1557 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar *)s.c_str()) < 0)
1558 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
1559
1560 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1561 throw InternalErr(__FILE__, __LINE__, "Could not end value element");
1562 }
1563 } else {
1564 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1565 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"value") < 0)
1566 throw InternalErr(__FILE__, __LINE__, "Could not write value element");
1567
1568 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar *)get_attr(i, j).c_str()) < 0)
1569 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
1570
1571 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1572 throw InternalErr(__FILE__, __LINE__, "Could not end value element");
1573 }
1574 }
1575 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1576 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
1577 }
1578 }
1579}
1580
1587
1595void AttrTable::dump(ostream &strm) const {
1596 strm << DapIndent::LMarg << "AttrTable::dump - (" << (void *)this << ")" << endl;
1598 strm << DapIndent::LMarg << "table name: " << d_name << endl;
1599 if (attr_map.size()) {
1600 strm << DapIndent::LMarg << "attributes: " << endl;
1602 Attr_citer i = attr_map.begin();
1603 Attr_citer ie = attr_map.end();
1604 for (; i != ie; ++i) {
1605 entry *e = (*i);
1606 string type = AttrType_to_String(e->type);
1607 if (e->is_alias) {
1608 strm << DapIndent::LMarg << "alias: " << e->name << " aliased to: " << e->aliased_to << endl;
1609 } else if (e->type == Attr_container) {
1610 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
1612 e->attributes->dump(strm);
1614 } else {
1615 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
1617 strm << DapIndent::LMarg;
1618 vector<string>::const_iterator iter = e->attr->begin();
1619 vector<string>::const_iterator last = e->attr->end() - 1;
1620 for (; iter != last; ++iter) {
1621 strm << (*iter) << ", ";
1622 }
1623 strm << (*(e->attr->end() - 1)) << endl;
1625 }
1626 }
1628 } else {
1629 strm << DapIndent::LMarg << "attributes: empty" << endl;
1630 }
1631 if (d_parent) {
1632 strm << DapIndent::LMarg << "parent table:" << d_name << ":" << (void *)d_parent << endl;
1633 } else {
1634 strm << DapIndent::LMarg << "parent table: none" << d_name << endl;
1635 }
1637}
1638
1639} // namespace libdap
Contains the attributes for a dataset.
Definition AttrTable.h:150
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition AttrTable.cc:517
bool is_dap4_type(const std::string &path, std::vector< std::string > &inventory) const
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:721
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:818
virtual void find(const string &target, AttrTable **at, Attr_iter *iter)
Definition AttrTable.cc:586
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition AttrTable.cc:247
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition AttrTable.cc:699
void clone(const AttrTable &at)
Definition AttrTable.cc:182
AttrTable & operator=(const AttrTable &rhs)
Definition AttrTable.cc:224
virtual Attr_iter attr_end()
Definition AttrTable.cc:798
virtual void print_xml(FILE *out, string pad=" ", bool constrained=false)
virtual string get_attr(const string &name, unsigned int i=0)
Definition AttrTable.cc:918
AttrTable * simple_find_container(const string &target)
Definition AttrTable.cc:677
virtual string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition AttrTable.cc:702
virtual bool is_global_attribute() const
Definition AttrTable.h:300
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition AttrTable.cc:738
virtual void add_value_alias(AttrTable *at, const string &name, const string &source)
Add an alias for an attribute.
Definition AttrTable.cc:997
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition AttrTable.cc:308
virtual Attr_iter attr_begin()
Definition AttrTable.cc:793
virtual Attr_iter get_attr_iter(int i)
Definition AttrTable.cc:808
void print_dap4(XMLWriter &xml)
virtual void del_attr(const string &name, int i=-1)
Deletes an attribute.
Definition AttrTable.cc:759
virtual string get_name() const
Get the name of this attribute table.
Definition AttrTable.cc:243
virtual void erase()
Erase the attribute table.
virtual void set_is_global_attribute(bool ga)
Definition AttrTable.h:301
void print_xml_writer(XMLWriter &xml)
virtual Attr_iter del_attr_table(Attr_iter iter)
Definition AttrTable.cc:848
virtual ~AttrTable()
Definition AttrTable.cc:222
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.
Definition AttrTable.cc:963
virtual unsigned int get_size() const
Get the number of entries in this attribute table.
Definition AttrTable.cc:239
virtual void dump(ostream &strm) const
dumps information about this object
std::vector< entry * >::const_iterator Attr_citer
Definition AttrTable.h:257
virtual AttrTable * find_container(const string &target)
Find an attribute with a given name.
Definition AttrTable.cc:663
Attr_iter simple_find(const string &target)
Definition AttrTable.cc:640
std::vector< entry * >::iterator Attr_iter
Definition AttrTable.h:258
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition AttrTable.cc:709
virtual AttrTable * recurrsive_find(const string &target, Attr_iter *location)
Definition AttrTable.cc:614
static ostream & LMarg(ostream &strm)
Definition DapIndent.cc:61
static void Indent()
Definition DapIndent.cc:44
static void UnIndent()
Definition DapIndent.cc:46
libdap base object for common functionality of libdap objects
Definition DapObj.h:49
A class for error processing.
Definition Error.h:92
A class for software fault reporting.
Definition InternalErr.h:61
unsigned int get_doc_size()
Definition XMLWriter.cc:123
const char * get_doc()
Definition XMLWriter.cc:104
xmlTextWriterPtr get_writer() const
Definition XMLWriter.h:55
STL iterator class.
STL iterator class.
#define DBG(x)
Definition debug.h:58
top level DAP object to house generic methods
Definition AISConnect.cc:30
string escattr(string s)
Definition escaping.cc:342
string escattr_xml(string s)
Definition escaping.cc:375
string www2id(const string &in, const string &escape, const string &except)
Definition escaping.cc:202
string id2xml(string in, const string &not_allowed)
Definition escaping.cc:253
string add_space_encoding(const string &s)
Definition AttrTable.cc:76
AttrType String_to_AttrType(const string &s)
Definition AttrTable.cc:136
void downcase(string &s)
Definition util.cc:544
string AttrType_to_String(const AttrType at)
Definition AttrTable.cc:93
const string double_quote
string escape_double_quotes(string source)
Definition escaping.cc:466
string remove_space_encoding(const string &s)
Definition AttrTable.cc:61
@ Attr_float32
Definition AttrTable.h:86
@ Attr_container
Definition AttrTable.h:80
@ Attr_enum
Definition AttrTable.h:99
@ Attr_uint64
Definition AttrTable.h:97
@ Attr_string
Definition AttrTable.h:88
@ Attr_int8
Definition AttrTable.h:93
@ Attr_unknown
Definition AttrTable.h:79
@ Attr_int32
Definition AttrTable.h:84
@ Attr_uint32
Definition AttrTable.h:85
@ Attr_url
Definition AttrTable.h:89
@ Attr_other_xml
Definition AttrTable.h:90
@ Attr_uint8
Definition AttrTable.h:94
@ Attr_opaque
Definition AttrTable.h:100
@ Attr_uint16
Definition AttrTable.h:83
@ Attr_float64
Definition AttrTable.h:87
@ Attr_int64
Definition AttrTable.h:96
@ Attr_byte
Definition AttrTable.h:81
@ Attr_int16
Definition AttrTable.h:82
bool is_quoted(const string &s)
Definition util.cc:554
string id2www(string in, const string &allowable)
Definition escaping.cc:143
std::vector< string > * attr
Definition AttrTable.h:172