libdap Updated for version 3.18.1
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
43#include "debug.h"
44
45// Should the www2id and id2www functions be used to encode attribute names?
46// Probably not... jhrg 11/16/11
47#define WWW_ENCODING 0
48// See the note for del_attr_table(). That method now deletes the contained
49// AttrTable.
50#define NEW_DEL_ATTR_TABLE_BEHAVIOR 0
51
52using std::cerr;
53using std::string;
54using std::endl;
55using std::vector;
56
57namespace libdap {
58
60static string remove_space_encoding(const string &s)
61{
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 }
71 else {
72 return s;
73 }
74}
75
77static string add_space_encoding(const string &s)
78{
79 string::size_type pos = s.find(" ");
80 if (pos != string::npos) {
81 string n = s;
82 do {
83 n.replace(pos, 1, "%20");
84 pos = n.find(" ");
85 } while (pos != string::npos);
86 return n;
87 }
88 else {
89 return s;
90 }
91}
92
97{
98 switch (at) {
99 case Attr_container:
100 return "Container";
101 case Attr_byte:
102 return "Byte";
103 case Attr_int16:
104 return "Int16";
105 case Attr_uint16:
106 return "UInt16";
107 case Attr_int32:
108 return "Int32";
109 case Attr_uint32:
110 return "UInt32";
111 case Attr_float32:
112 return "Float32";
113 case Attr_float64:
114 return "Float64";
115 case Attr_string:
116 return "String";
117 case Attr_url:
118 return "Url";
119 case Attr_other_xml:
120 return "OtherXML";
121 default:
122 return "";
123 }
124}
125
126AttrType String_to_AttrType(const string &s)
127{
128 string s2 = s;
129 downcase(s2);
130
131 if (s2 == "container")
132 return Attr_container;
133 else if (s2 == "byte")
134 return Attr_byte;
135 else if (s2 == "int16")
136 return Attr_int16;
137 else if (s2 == "uint16")
138 return Attr_uint16;
139 else if (s2 == "int32")
140 return Attr_int32;
141 else if (s2 == "uint32")
142 return Attr_uint32;
143 else if (s2 == "float32")
144 return Attr_float32;
145 else if (s2 == "float64")
146 return Attr_float64;
147 else if (s2 == "string")
148 return Attr_string;
149 else if (s2 == "url")
150 return Attr_url;
151 else if (s2 == "otherxml")
152 return Attr_other_xml;
153 else
154 return Attr_unknown;
155}
156
160{
161 d_name = at.d_name;
162 d_is_global_attribute = at.d_is_global_attribute;
163
164 // Set the parent to null (no parent, not in container)
165 // since using at.d_parent is semantically incorrect
166 // and potentially dangerous.
167 d_parent = 0;
168
169 Attr_citer i = at.attr_map.begin();
170 Attr_citer ie = at.attr_map.end();
171 for (; i != ie; ++i) {
172 // this deep-copies containers recursively
173 entry *e = new entry(*(*i));
174 attr_map.push_back(e);
175
176 // If the entry being added was a container,
177 // set its parent to this to maintain invariant.
178 if (e->type == Attr_container) {
179 assert(e->attributes);
180 e->attributes->d_parent = this;
181 }
182 }
183}
184
188AttrTable::AttrTable() :
189 DapObj(), d_name(""), d_parent(0), attr_map(), d_is_global_attribute(true)
190{
191}
192
193AttrTable::AttrTable(const AttrTable &rhs) :
194 DapObj()
195{
196 clone(rhs);
197}
198
199// Private
200void AttrTable::delete_attr_table()
201{
202 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
203 delete *i;
204 }
205 attr_map.clear();
206}
207
208AttrTable::~AttrTable()
209{
210 delete_attr_table();
211}
212
213AttrTable &
214AttrTable::operator=(const AttrTable &rhs)
215{
216 if (this != &rhs) {
217 delete_attr_table();
218 clone(rhs);
219 }
220
221 return *this;
222}
224
230unsigned int AttrTable::get_size() const
231{
232 return attr_map.size();
233}
234
238{
239 return d_name;
240}
241
244void AttrTable::set_name(const string &n)
245{
246#if WWW_ENCODING
247 d_name = www2id(n);
248#else
249 d_name = remove_space_encoding(n);
250#endif
251}
252
253#if 0
254// This was taken from das.y and could be used here to make the 'dods_errors'
255// attribute container like the parser used to. Then again, maybe this feature
256// was just BS. jhrg (ticket 1469)
257static void add_bad_attribute(AttrTable *attr, const string &type, const string &name, const string &value,
258 const string &msg) {
259 // First, if this bad value is already in a *_dods_errors container,
260 // then just add it. This can happen when the server side processes a DAS
261 // and then hands it off to a client which does the same.
262 // Make a new container. Call it <attr's name>_errors. If that container
263 // already exists, use it.
264 // Add the attribute.
265 // Add the error string to an attribute in the container called
266 // `<name_explanation.'.
267
268 if (attr->get_name().find("_dods_errors") != string::npos) {
269 attr->append_attr(name, type, value);
270 }
271 else {
272 // I think _dods_errors should be _dap_error. jhrg 11/16/11
273 string error_cont_name = attr->get_name() + "_dods_errors";
274 AttrTable *error_cont = attr->get_attr_table(error_cont_name);
275 if (!error_cont)
276 error_cont = attr->append_container(error_cont_name);
277
278 error_cont->append_attr(name, type, value);
279
280#ifndef ATTR_STRING_QUOTE_FIX
281 error_cont->append_attr(name + "_dap_explanation", "String", "\"" + msg + "\"");
282#else
283 error_cont->append_attr(name + "_dap_explanation", "String", msg);
284#endif
285 }
286}
287#endif
288
306unsigned int AttrTable::append_attr(const string &name, const string &type, const string &value)
307{
308 DBG(cerr << "Entering AttrTable::append_attr" << endl);
309#if WWW_ENCODING
310 string lname = www2id(name);
311#else
312 string lname = remove_space_encoding(name);
313#endif
314
315 Attr_iter iter = simple_find(lname);
316
317 // If the types don't match OR this attribute is a container, calling
318 // this mfunc is an error!
319 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
320 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
321 if (iter != attr_map.end() && (get_type(iter) == "Container"))
322 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
323
324 if (iter != attr_map.end()) { // Must be a new attribute value; add it.
325 (*iter)->attr->push_back(value);
326 return (*iter)->attr->size();
327 }
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
361unsigned int AttrTable::append_attr(const string &name, const string &type, vector<string> *values)
362{
363 DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl);
364#if WWW_ENCODING
365 string lname = www2id(name);
366#else
367 string lname = remove_space_encoding(name);
368#endif
369 Attr_iter iter = simple_find(lname);
370
371 // If the types don't match OR this attribute is a container, calling
372 // this mfunc is an error!
373 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
374 throw Error(string("An attribute called `") + name + string("' already exists but is of a different type"));
375 if (iter != attr_map.end() && (get_type(iter) == "Container"))
376 throw Error(string("An attribute called `") + name + string("' already exists but is a container."));
377
378 if (iter != attr_map.end()) { // Must be new attribute values; add.
379 vector<string>::iterator i = values->begin();
380 while (i != values->end())
381 (*iter)->attr->push_back(*i++);
382
383 return (*iter)->attr->size();
384 }
385 else { // Must be a completely new attribute; add it
386 entry *e = new entry;
387
388 e->name = lname;
389 e->is_alias = false;
390 e->type = String_to_AttrType(type); // Record type using standard names.
391 e->attr = new vector<string> (*values);
392
393 attr_map.push_back(e);
394
395 return e->attr->size(); // return the length of the attr vector
396 }
397}
398
408AttrTable *
410{
411 AttrTable *new_at = new AttrTable;
412 AttrTable *ret = NULL;
413 try {
414 ret = append_container(new_at, name);
415 } catch (Error &e) {
416 // an error occurred, attribute with that name already exists
417 delete new_at;
418 new_at = 0;
419 throw;
420 }
421 return ret;
422}
423
438AttrTable *
440{
441#if WWW_ENCODING
442 string lname = www2id(name);
443#else
444 string lname = remove_space_encoding(name);
445#endif
446
447 if (simple_find(name) != attr_end())
448 throw Error("There already exists a container called '" + name + "' in this attribute table (" + at->get_name() + "). (1)");
449
450 DBG(cerr << "Setting appended attribute container name to: " << lname << endl);
451 at->set_name(lname);
452
453 entry *e = new entry;
454 e->name = lname;
455 e->is_alias = false;
456 e->type = Attr_container;
457 e->attributes = at;
458
459 attr_map.push_back(e);
460
461 at->d_parent = this;
462
463 return e->attributes;
464}
465
480void AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter)
481{
482 string::size_type dotpos = target.rfind('.');
483 if (dotpos != string::npos) {
484 string container = target.substr(0, dotpos);
485 string field = target.substr(dotpos + 1);
486
487 *at = find_container(container);
488 if (*at) {
489 *iter = (*at)->simple_find(field);
490 }
491 else {
492 *iter = attr_map.end();
493 }
494 }
495 else {
496 *at = recurrsive_find(target, iter);
497 }
498}
499
511AttrTable *
512AttrTable::recurrsive_find(const string &target, Attr_iter *location)
513{
514 Attr_iter i = attr_begin();
515 while (i != attr_end()) {
516 if (target == (*i)->name) {
517 *location = i;
518 return this;
519 }
520 else if ((*i)->type == Attr_container) {
521 AttrTable *at = (*i)->attributes->recurrsive_find(target, location);
522 if (at)
523 return at;
524 }
525
526 ++i;
527 }
528
529 *location = i;
530 return 0;
531}
532
533// Made public for callers that want non-recursive find. [mjohnson 6 oct 09]
540AttrTable::Attr_iter AttrTable::simple_find(const string &target)
541{
542 Attr_iter i;
543 for (i = attr_map.begin(); i != attr_map.end(); ++i) {
544 if (target == (*i)->name) {
545 break;
546 }
547 }
548 return i;
549}
550
564AttrTable *
565AttrTable::find_container(const string &target)
566{
567 string::size_type dotpos = target.find('.');
568 if (dotpos != string::npos) {
569 string container = target.substr(0, dotpos);
570 string field = target.substr(dotpos + 1);
571
572 AttrTable *at = simple_find_container(container);
573 return (at) ? at->find_container(field) : 0;
574 }
575 else {
576 return simple_find_container(target);
577 }
578}
579
580// Made public for callers that want non-recursive find. [mjohnson 6 oct 09]
581AttrTable *
582AttrTable::simple_find_container(const string &target)
583{
584 if (get_name() == target)
585 return this;
586
587 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
588 if (is_container(i) && target == (*i)->name) {
589 return (*i)->attributes;
590 }
591 }
592
593 return 0;
594}
595
603
605AttrTable *
606AttrTable::get_attr_table(const string &name)
607{
608 return find_container(name);
609}
610
612string AttrTable::get_type(const string &name)
613{
614 Attr_iter p = simple_find(name);
615 return (p != attr_map.end()) ? get_type(p) : (string) "";
616}
617
621{
622 Attr_iter p = simple_find(name);
623 return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown;
624}
625
633unsigned int AttrTable::get_attr_num(const string &name)
634{
635 Attr_iter iter = simple_find(name);
636 return (iter != attr_map.end()) ? get_attr_num(iter) : 0;
637}
638
651vector<string> *
652AttrTable::get_attr_vector(const string &name)
653{
654 Attr_iter p = simple_find(name);
655 return (p != attr_map.end()) ? get_attr_vector(p) : 0;
656}
657
674void AttrTable::del_attr(const string &name, int i)
675{
676#if WWW_ENCODING
677 string lname = www2id(name);
678#else
679 string lname = remove_space_encoding(name);
680#endif
681
682 Attr_iter iter = simple_find(lname);
683 if (iter != attr_map.end()) {
684 if (i == -1) { // Delete the whole attribute
685 entry *e = *iter;
686 attr_map.erase(iter);
687 delete e;
688 e = 0;
689 }
690 else { // Delete one element from attribute array
691 // Don't try to delete elements from the vector of values if the
692 // map is a container!
693 if ((*iter)->type == Attr_container)
694 return;
695
696 vector<string> *sxp = (*iter)->attr;
697
698 assert(i >= 0 && i < (int) sxp->size());
699 sxp->erase(sxp->begin() + i); // rm the element
700 }
701 }
702}
703
705
710AttrTable::Attr_iter AttrTable::attr_begin()
711{
712 return attr_map.begin();
713}
714
718AttrTable::Attr_iter AttrTable::attr_end()
719{
720 return attr_map.end();
721}
722
731AttrTable::Attr_iter AttrTable::get_attr_iter(int i)
732{
733 return attr_map.begin() + i;
734}
735
737string AttrTable::get_name(Attr_iter iter)
738{
739 assert(iter != attr_map.end());
740
741 return (*iter)->name;
742}
743
745bool AttrTable::is_container(Attr_iter i)
746{
747 return (*i)->type == Attr_container;
748}
749
755AttrTable *
757{
758 assert(iter != attr_map.end());
759 return (*iter)->type == Attr_container ? (*iter)->attributes : 0;
760}
761
780AttrTable::Attr_iter AttrTable::del_attr_table(Attr_iter iter)
781{
782 if ((*iter)->type != Attr_container)
783 return ++iter;
784
785 // the caller intends to delete/reuse the contained AttrTable,
786 // so zero it out so it doesn't get deleted before we delete the entry
787 // [mjohnson]
788 struct entry *e = *iter;
789 // container no longer has a parent.
790 if (e->attributes) {
791 e->attributes->d_parent = 0;
792
793#if NEW_DEL_ATTR_TABLE_BEHAVIOR
794 delete e->attributes;
795#endif
796 e->attributes = 0;
797 }
798
799 delete e;
800
801 return attr_map.erase(iter);
802}
803
807string AttrTable::get_type(Attr_iter iter)
808{
809 assert(iter != attr_map.end());
810 return AttrType_to_String((*iter)->type);
811}
812
817{
818 return (*iter)->type;
819}
820
828unsigned int AttrTable::get_attr_num(Attr_iter iter)
829{
830 assert(iter != attr_map.end());
831 return ((*iter)->type == Attr_container) ? (*iter)->attributes->get_size() : (*iter)->attr->size();
832}
833
850string AttrTable::get_attr(Attr_iter iter, unsigned int i)
851{
852 assert(iter != attr_map.end());
853
854 return (*iter)->type == Attr_container ? (string) "None" : (*(*iter)->attr)[i];
855}
856
857string AttrTable::get_attr(const string &name, unsigned int i)
858{
859 Attr_iter p = simple_find(name);
860 return (p != attr_map.end()) ? get_attr(p, i) : (string) "";
861}
862
874vector<string> *
876{
877 assert(iter != attr_map.end());
878 return (*iter)->type != Attr_container ? (*iter)->attr : 0;
879}
880
881bool AttrTable::is_global_attribute(Attr_iter iter)
882{
883 assert(iter != attr_map.end());
884 if ((*iter)->type == Attr_container)
885 return (*iter)->attributes->is_global_attribute();
886 else
887 return (*iter)->is_global;
888}
889
890void AttrTable::set_is_global_attribute(Attr_iter iter, bool ga)
891{
892 assert(iter != attr_map.end());
893 if ((*iter)->type == Attr_container)
894 (*iter)->attributes->set_is_global_attribute(ga);
895 else
896 (*iter)->is_global = ga;
897}
898
900
901// Alias an attribute table. The alias should be added to this object.
907void AttrTable::add_container_alias(const string &name, AttrTable *src)
908{
909#if WWW_ENCODING
910 string lname = www2id(name);
911#else
912 string lname = remove_space_encoding(name);
913#endif
914
915 if (simple_find(lname) != attr_end())
916 throw Error(string("There already exists a container called `") + name + string("in this attribute table. (2)"));
917
918 entry *e = new entry;
919 e->name = lname;
920 e->is_alias = true;
921 e->aliased_to = src->get_name();
922 e->type = Attr_container;
923
924 e->attributes = src;
925
926 attr_map.push_back(e);
927}
928
941void AttrTable::add_value_alias(AttrTable *das, const string &name, const string &source)
942{
943#if WWW_ENCODING
944 string lname = www2id(name);
945#else
946 string lname = remove_space_encoding(name);
947#endif
948
949#if WWW_ENCODING
950 string lsource = www2id(source);
951#else
952 string lsource = remove_space_encoding(source);
953#endif
954
955 // find the container that holds source and its (sources's) iterator
956 // within that container. Search at the uppermost level of the attribute
957 // object to find values defined `above' the current container.
958 AttrTable *at;
959 Attr_iter iter;
960 das->find(lsource, &at, &iter);
961
962 // If source is not found by looking at the topmost level, look in the
963 // current table (i.e., alias z x where x is in the current container
964 // won't be found by looking for `x' at the top level). See test case 26
965 // in das-testsuite.
966 if (!at || (iter == at->attr_end()) || !*iter) {
967 find(lsource, &at, &iter);
968 if (!at || (iter == at->attr_end()) || !*iter)
969 throw Error(string("Could not find the attribute `") + source + string("' in the attribute object."));
970 }
971
972 // If we've got a value to alias and it's being added at the top level of
973 // the DAS, that's an error.
974 if (at && !at->is_container(iter) && this == das)
975 throw Error(
976 string(
977 "A value cannot be aliased to the top level of the DAS;\nOnly containers may be present at that level of the DAS."));
978
979 if (simple_find(lname) != attr_end())
980 throw Error(string("There already exists a container called `") + name + string("in this attribute table. (3)"));
981
982 entry *e = new entry;
983 e->name = lname;
984 e->is_alias = true;
985 e->aliased_to = lsource;
986 e->type = get_attr_type(iter);
987 if (at && e->type == Attr_container)
988 e->attributes = at->get_attr_table(iter);
989 else
990 e->attr = (*iter)->attr;
991
992 attr_map.push_back(e);
993}
994
995// Deprecated
1014bool AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name)
1015{
1016 add_value_alias(at, alias, name);
1017 return true;
1018}
1019
1027bool AttrTable::attr_alias(const string &alias, const string &name)
1028{
1029 return attr_alias(alias, this, name);
1030}
1031
1036{
1037 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1038 delete *i;
1039 *i = 0;
1040 }
1041
1042 attr_map.erase(attr_map.begin(), attr_map.end());
1043
1044 d_name = "";
1045}
1046
1047const string double_quote = "\"";
1048
1049// This is here as a result of the problem described in ticket #1163 where
1050// the data handlers are adding quotes to string attributes so the DAS will
1051// be printed correctly. But that has the affect of adding the quotes to the
1052// attribute's _value_ not just it's print representation. As part of the fix
1053// I made the code here add the quotes if the handlers are fixed (but not if
1054// handlers are still adding them). The other part of 1163 is to fix all of
1055// the handlers... What this fix means is that attributes whose values really
1056// do contain bracketing quotes might be misunderstood, since we're assuming
1057// those quotes were added by the handlers as a hack to get the output
1058// formatting correct for the DAS. jhrg 7/30/08
1059
1060static void write_string_attribute_for_das(ostream &out, const string &value, const string &term)
1061{
1062 if (is_quoted(value))
1063 out << value << term;
1064 else
1065 out << double_quote << value << double_quote << term;
1066}
1067
1068#if 0
1069static void
1070write_string_attribute_for_das(FILE *out, const string &value, const string &term)
1071{
1072 if (is_quoted(value))
1073 fprintf(out, "%s%s", value.c_str(), term.c_str());
1074 else
1075 fprintf(out, "\"%s\"%s", value.c_str(), term.c_str());
1076}
1077#endif
1078
1079// Special treatment for XML: Make sure to escape double quotes when XML is
1080// printed in a DAS.
1081static void write_xml_attribute_for_das(ostream &out, const string &value, const string &term)
1082{
1083 if (is_quoted(value))
1084 out << escape_double_quotes(value) << term;
1085 else
1086 out << double_quote << escape_double_quotes(value) << double_quote << term;
1087}
1088
1089#if 0
1090static void
1091write_xml_attribute_for_das(FILE *out, const string &value, const string &term)
1092{
1093 if (is_quoted(value))
1094 fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str());
1095 else
1096 fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str());
1097}
1098#endif
1099
1102void AttrTable::simple_print(FILE *out, string pad, Attr_iter i, bool dereference)
1103{
1104 ostringstream oss;
1105 simple_print(oss, pad, i, dereference);
1106 fwrite(oss.str().data(), 1, oss.str().length(), out);
1107
1108#if 0
1109 switch ((*i)->type) {
1110 case Attr_container:
1111#if WWW_ENCODING
1112 fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str());
1113#else
1114 fprintf(out, "%s%s {\n", pad.c_str(), get_name(i).c_str());
1115#endif
1116 (*i)->attributes->print(out, pad + " ", dereference);
1117
1118 fprintf(out, "%s}\n", pad.c_str());
1119 break;
1120
1121 case Attr_string: {
1122#if WWW_ENCODING
1123 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1124#else
1125 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1126#endif
1127 vector<string> *sxp = (*i)->attr;
1128 vector<string>::iterator last = sxp->end() - 1;
1129 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1130 write_string_attribute_for_das(out, *i, ", ");
1131 }
1132 write_string_attribute_for_das(out, *last, ";\n");
1133 }
1134 break;
1135
1136 case Attr_other_xml: {
1137#if WWW_ENCODING
1138 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1139#else
1140 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1141#endif
1142 vector<string> *sxp = (*i)->attr;
1143 vector<string>::iterator last = sxp->end() - 1;
1144 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1145 write_xml_attribute_for_das(out, *i, ", ");
1146 }
1147 write_xml_attribute_for_das(out, *last, ";\n");
1148 }
1149 break;
1150
1151 default: {
1152#if WWW_ENCODING
1153 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), id2www(get_name(i)).c_str());
1154#else
1155 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), get_name(i).c_str());
1156#endif
1157
1158 vector<string> *sxp = (*i)->attr;
1159 vector<string>::iterator last = sxp->end() - 1;
1160 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1161 fprintf(out, "%s%s", (*i).c_str(), ", ");
1162 }
1163 fprintf(out, "%s%s", (*last).c_str(), ";\n");
1164 }
1165 break;
1166 }
1167#endif
1168}
1169
1172void AttrTable::simple_print(ostream &out, string pad, Attr_iter i, bool dereference)
1173{
1174 switch ((*i)->type) {
1175 case Attr_container:
1176#if WWW_ENCODING
1177 out << pad << id2www(get_name(i)) << " {\n";
1178#else
1179 out << pad << add_space_encoding(get_name(i)) << " {\n";
1180#endif
1181 (*i)->attributes->print(out, pad + " ", dereference);
1182 out << pad << "}\n";
1183 break;
1184
1185 case Attr_string: {
1186#if WWW_ENCODING
1187 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1188#else
1189 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1190#endif
1191 vector<string> *sxp = (*i)->attr;
1192 vector<string>::iterator last = sxp->end() - 1;
1193 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1194 write_string_attribute_for_das(out, *i, ", ");
1195 }
1196 write_string_attribute_for_das(out, *last, ";\n");
1197 }
1198 break;
1199
1200 case Attr_other_xml: {
1201#if WWW_ENCODING
1202 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1203#else
1204 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1205#endif
1206 vector<string> *sxp = (*i)->attr;
1207 vector<string>::iterator last = sxp->end() - 1;
1208 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1209 write_xml_attribute_for_das(out, *i, ", ");
1210 }
1211 write_xml_attribute_for_das(out, *last, ";\n");
1212 }
1213 break;
1214
1215 default: {
1216#if WWW_ENCODING
1217 out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
1218#else
1219 out << pad << get_type(i) << " " << add_space_encoding(get_name(i)) << " ";
1220#endif
1221 vector<string> *sxp = (*i)->attr;
1222 vector<string>::iterator last = sxp->end() - 1;
1223 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
1224 out << *i << ", ";
1225 }
1226 out << *last << ";\n";
1227 }
1228 break;
1229 }
1230}
1231
1242void AttrTable::print(FILE *out, string pad, bool dereference)
1243{
1244 ostringstream oss;
1245 print(oss, pad, dereference);
1246 fwrite(oss.str().data(), 1, oss.str().length(), out);
1247
1248#if 0
1249 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1250 if ((*i)->is_alias) {
1251 if (dereference) {
1252 simple_print(out, pad, i, dereference);
1253 }
1254 else {
1255#if WWW_ENCODING
1256 fprintf(out, "%sAlias %s %s;\n",
1257 pad.c_str(),
1258 id2www(get_name(i)).c_str(),
1259 id2www((*i)->aliased_to).c_str());
1260#else
1261 fprintf(out, "%sAlias %s %s;\n",
1262 pad.c_str(), add_space_encoding(get_name(i)).c_str(), add_space_encoding((*i)->aliased_to).c_str());
1263
1264#endif
1265 }
1266 }
1267 else {
1268 simple_print(out, pad, i, dereference);
1269 }
1270 }
1271#endif
1272}
1273
1284void AttrTable::print(ostream &out, string pad, bool dereference)
1285{
1286 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
1287 if ((*i)->is_alias) {
1288 if (dereference) {
1289 simple_print(out, pad, i, dereference);
1290 }
1291 else {
1292#if WWW_ENCODING
1293 out << pad << "Alias " << id2www(get_name(i))
1294 << " " << id2www((*i)->aliased_to) << ";\n";
1295#else
1296 out << pad << "Alias " << add_space_encoding(get_name(i)) << " "
1297 << add_space_encoding((*i)->aliased_to) << ";\n";
1298#endif
1299 }
1300 }
1301 else {
1302 simple_print(out, pad, i, dereference);
1303 }
1304 }
1305}
1306
1312void AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/)
1313{
1314 XMLWriter xml(pad);
1315 print_xml_writer(xml);
1316 fwrite(xml.get_doc(), sizeof(char), xml.get_doc_size(), out);
1317
1318#if OLD_XML_MOETHODS
1319 ostringstream oss;
1320 print_xml(oss, pad);
1321 fwrite(oss.str().data(), 1, oss.str().length(), out);
1322#endif
1323
1324#if 0
1325 // Why this works: AttrTable is really a hacked class that used to
1326 // implement a single-level set of attributes. Containers
1327 // were added several years later by dropping in the 'entry' structure.
1328 // It's not a class in its own right; instead accessors from AttrTable
1329 // are used to access information from entry. So... the loop below
1330 // actually iterates over the entries of *this* (which is an instance of
1331 // AttrTable). A container is an entry whose sole value is an AttrTable
1332 // instance. 05/19/03 jhrg
1333 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1334 if ((*i)->is_alias) {
1335 fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n",
1336 pad.c_str(), id2xml(get_name(i)).c_str(),
1337 (*i)->aliased_to.c_str());
1338
1339 }
1340 else if (is_container(i)) {
1341 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
1342 pad.c_str(), id2xml(get_name(i)).c_str(),
1343 get_type(i).c_str());
1344
1345 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/);
1346
1347 fprintf(out, "%s</Attribute>\n", pad.c_str());
1348 }
1349 else {
1350 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
1351 pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str());
1352
1353 string value_pad = pad + " ";
1354 // Special handling for the OtherXML attribute type - don't escape
1355 // the XML and don't include the <value> element. Note that there
1356 // cannot be an vector of XML things as can be with the other types.
1357 if (get_attr_type(i) == Attr_other_xml) {
1358 if (get_attr_num(i) != 1)
1359 throw Error("OtherXML attributes cannot be vector-valued.");
1360 fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str());
1361 }
1362 else {
1363 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1364 fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(),
1365 id2xml(get_attr(i, j)).c_str());
1366 }
1367 }
1368 fprintf(out, "%s</Attribute>\n", pad.c_str());
1369 }
1370 }
1371#endif
1372}
1373
1377void AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/)
1378{
1379 XMLWriter xml(pad);
1380 print_xml_writer(xml);
1381 out << xml.get_doc();
1382
1383#if 0
1384 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1385 if ((*i)->is_alias) {
1386 out << pad << "<Alias name=\"" << id2xml(get_name(i))
1387 << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n";
1388
1389 }
1390 else if (is_container(i)) {
1391 out << pad << "<Attribute name=\"" << id2xml(get_name(i))
1392 << "\" type=\"" << get_type(i) << "\">\n";
1393
1394 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/);
1395
1396 out << pad << "</Attribute>\n";
1397 }
1398 else {
1399 out << pad << "<Attribute name=\"" << id2xml(get_name(i))
1400 << "\" type=\"" << get_type(i) << "\">\n";
1401
1402 string value_pad = pad + " ";
1403 if (get_attr_type(i) == Attr_other_xml) {
1404 if (get_attr_num(i) != 1)
1405 throw Error("OtherXML attributes cannot be vector-valued.");
1406 out << value_pad << get_attr(i, 0) << "\n";
1407 }
1408 else {
1409 string value_pad = pad + " ";
1410 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1411 out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n";
1412 }
1413 }
1414 out << pad << "</Attribute>\n";
1415 }
1416 }
1417#endif
1418}
1419
1425{
1426 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
1427 if ((*i)->is_alias) {
1428 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Alias") < 0)
1429 throw InternalErr(__FILE__, __LINE__, "Could not write Alias element");
1430 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1431 (const xmlChar*) get_name(i).c_str()) < 0)
1432 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1433 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "Attribute",
1434 (const xmlChar*) (*i)->aliased_to.c_str()) < 0)
1435 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1436 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1437 throw InternalErr(__FILE__, __LINE__, "Could not end Alias element");
1438 }
1439 else if (is_container(i)) {
1440 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
1441 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
1442 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1443 (const xmlChar*) get_name(i).c_str()) < 0)
1444 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1445 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type",
1446 (const xmlChar*) get_type(i).c_str()) < 0)
1447 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1448
1450
1451 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1452 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
1453 }
1454 else {
1455 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
1456 throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
1457 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name",
1458 (const xmlChar*) get_name(i).c_str()) < 0)
1459 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1460 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type",
1461 (const xmlChar*) get_type(i).c_str()) < 0)
1462 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1463
1464 if (get_attr_type(i) == Attr_other_xml) {
1465 if (get_attr_num(i) != 1)
1466 throw Error("OtherXML attributes cannot be vector-valued.");
1467 // Replaced xmltextWriterWriteString with xmlTextWriterWriteRaw to keep the
1468 // libxml2 code from escaping the xml (which was breaking all of the inferencing
1469 // code. jhrg
1470 if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) get_attr(i, 0).c_str()) < 0)
1471 throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
1472 }
1473 else {
1474 for (unsigned j = 0; j < get_attr_num(i); ++j) {
1475 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "value") < 0)
1476 throw InternalErr(__FILE__, __LINE__, "Could not write value element");
1477
1478 if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) get_attr(i, j).c_str()) < 0)
1479 throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
1480
1481 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1482 throw InternalErr(__FILE__, __LINE__, "Could not end value element");
1483 }
1484 }
1485 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1486 throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
1487 }
1488 }
1489}
1490
1496void
1498{
1499 print_xml_writer(xml);
1500}
1501
1509void AttrTable::dump(ostream &strm) const
1510{
1511 strm << DapIndent::LMarg << "AttrTable::dump - (" << (void *) this << ")" << endl;
1512 DapIndent::Indent();
1513 strm << DapIndent::LMarg << "table name: " << d_name << endl;
1514 if (attr_map.size()) {
1515 strm << DapIndent::LMarg << "attributes: " << endl;
1516 DapIndent::Indent();
1517 Attr_citer i = attr_map.begin();
1518 Attr_citer ie = attr_map.end();
1519 for (; i != ie; ++i) {
1520 entry *e = (*i);
1521 string type = AttrType_to_String(e->type);
1522 if (e->is_alias) {
1523 strm << DapIndent::LMarg << "alias: " << e->name << " aliased to: " << e->aliased_to << endl;
1524 }
1525 else if (e->type == Attr_container) {
1526 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
1527 DapIndent::Indent();
1528 e->attributes->dump(strm);
1529 DapIndent::UnIndent();
1530 }
1531 else {
1532 strm << DapIndent::LMarg << "attr: " << e->name << " of type " << type << endl;
1533 DapIndent::Indent();
1534 strm << DapIndent::LMarg;
1535 vector<string>::const_iterator iter = e->attr->begin();
1536 vector<string>::const_iterator last = e->attr->end() - 1;
1537 for (; iter != last; ++iter) {
1538 strm << (*iter) << ", ";
1539 }
1540 strm << (*(e->attr->end() - 1)) << endl;
1541 DapIndent::UnIndent();
1542 }
1543 }
1544 DapIndent::UnIndent();
1545 }
1546 else {
1547 strm << DapIndent::LMarg << "attributes: empty" << endl;
1548 }
1549 if (d_parent) {
1550 strm << DapIndent::LMarg << "parent table:" << d_name << ":" << (void *) d_parent << endl;
1551 }
1552 else {
1553 strm << DapIndent::LMarg << "parent table: none" << d_name << endl;
1554 }
1555 DapIndent::UnIndent();
1556}
1557
1558} // namespace libdap
1559
Contains the attributes for a dataset.
Definition: AttrTable.h:143
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:409
void simple_print(FILE *out, string pad, Attr_iter i, bool dereference)
Definition: AttrTable.cc:1102
virtual unsigned int get_attr_num(const string &name)
Get the number of attributes in this container.
Definition: AttrTable.cc:633
virtual bool attr_alias(const string &alias, AttrTable *at, const string &name)
Adds an alias to the set of attributes.
Definition: AttrTable.cc:1014
virtual bool is_container(Attr_iter iter)
Definition: AttrTable.cc:745
virtual void find(const string &target, AttrTable **at, Attr_iter *iter)
Definition: AttrTable.cc:480
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition: AttrTable.cc:244
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:606
void clone(const AttrTable &at)
Definition: AttrTable.cc:159
virtual Attr_iter attr_end()
Definition: AttrTable.cc:718
virtual void print_xml(FILE *out, string pad=" ", bool constrained=false)
Definition: AttrTable.cc:1312
virtual string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition: AttrTable.cc:612
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:652
virtual void add_value_alias(AttrTable *at, const string &name, const string &source)
Add an alias for an attribute.
Definition: AttrTable.cc:941
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:306
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:710
virtual Attr_iter get_attr_iter(int i)
Definition: AttrTable.cc:731
void print_dap4(XMLWriter &xml)
Definition: AttrTable.cc:1497
virtual void del_attr(const string &name, int i=-1)
Deletes an attribute.
Definition: AttrTable.cc:674
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:237
virtual void erase()
Erase the attribute table.
Definition: AttrTable.cc:1035
void print_xml_writer(XMLWriter &xml)
Definition: AttrTable.cc:1424
virtual Attr_iter del_attr_table(Attr_iter iter)
Definition: AttrTable.cc:780
virtual void print(FILE *out, string pad=" ", bool dereference=false)
Prints the attribute table.
Definition: AttrTable.cc:1242
virtual void add_container_alias(const string &name, AttrTable *src)
Add an alias to a container held by this attribute table.
Definition: AttrTable.cc:907
virtual unsigned int get_size() const
Get the number of entries in this attribute table.
Definition: AttrTable.cc:230
virtual void dump(ostream &strm) const
dumps information about this object
Definition: AttrTable.cc:1509
virtual AttrTable * find_container(const string &target)
Find an attribute with a given name.
Definition: AttrTable.cc:565
Attr_iter simple_find(const string &target)
Definition: AttrTable.cc:540
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition: AttrTable.cc:620
virtual AttrTable * recurrsive_find(const string &target, Attr_iter *location)
Definition: AttrTable.cc:512
libdap base object for common functionality of libdap objects
Definition: DapObj.h:56
A class for error processing.
Definition: Error.h:91
A class for software fault reporting.
Definition: InternalErr.h:65
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
void downcase(string &s)
Definition: util.cc:559
string AttrType_to_String(const AttrType at)
Definition: AttrTable.cc:96
string escape_double_quotes(string source)
Definition: escaping.cc:470
AttrType
Definition: AttrTable.h:81
bool is_quoted(const string &s)
Definition: util.cc:570
string id2www(string in, const string &allowable)
Definition: escaping.cc:153