libdap++
Updated for version 3.8.2
|
00001 // -*- mode: c++; c-basic-offset:4 -*- 00002 00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00004 // Access Protocol. 00005 00006 // Copyright (c) 2002,2003 OPeNDAP, Inc. 00007 // Author: James Gallagher <jgallagher@opendap.org> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00024 00025 // (c) COPYRIGHT URI/MIT 1994-1999 00026 // Please read the full copyright statement in the file COPYRIGHT_URI. 00027 // 00028 // Authors: 00029 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu> 00030 00031 // jhrg 7/29/94 00032 00033 #include "config.h" 00034 00035 // #define DODS_DEBUG 00036 00037 static char rcsid[]not_used = 00038 "$Id: AttrTable.cc 24370 2011-03-28 16:21:32Z jimg $"; 00039 00040 #include <cassert> 00041 00042 #include "AttrTable.h" 00043 00044 #include "util.h" 00045 #include "escaping.h" 00046 00047 #include "debug.h" 00048 00049 using std::cerr; 00050 using std::string; 00051 using std::endl; 00052 using std::vector; 00053 00054 namespace libdap { 00055 00059 string AttrType_to_String(const AttrType at) 00060 { 00061 switch (at) { 00062 case Attr_container: 00063 return "Container"; 00064 case Attr_byte: 00065 return "Byte"; 00066 case Attr_int16: 00067 return "Int16"; 00068 case Attr_uint16: 00069 return "UInt16"; 00070 case Attr_int32: 00071 return "Int32"; 00072 case Attr_uint32: 00073 return "UInt32"; 00074 case Attr_float32: 00075 return "Float32"; 00076 case Attr_float64: 00077 return "Float64"; 00078 case Attr_string: 00079 return "String"; 00080 case Attr_url: 00081 return "Url"; 00082 case Attr_other_xml: 00083 return "OtherXML"; 00084 default: 00085 return ""; 00086 } 00087 } 00088 00089 AttrType String_to_AttrType(const string &s) 00090 { 00091 string s2 = s; 00092 downcase(s2); 00093 00094 if (s2 == "container") 00095 return Attr_container; 00096 else if (s2 == "byte") 00097 return Attr_byte; 00098 else if (s2 == "int16") 00099 return Attr_int16; 00100 else if (s2 == "uint16") 00101 return Attr_uint16; 00102 else if (s2 == "int32") 00103 return Attr_int32; 00104 else if (s2 == "uint32") 00105 return Attr_uint32; 00106 else if (s2 == "float32") 00107 return Attr_float32; 00108 else if (s2 == "float64") 00109 return Attr_float64; 00110 else if (s2 == "string") 00111 return Attr_string; 00112 else if (s2 == "url") 00113 return Attr_url; 00114 else if (s2 == "otherxml") 00115 return Attr_other_xml; 00116 else 00117 return Attr_unknown; 00118 } 00119 00122 void AttrTable::clone(const AttrTable &at) 00123 { 00124 d_name = at.d_name; 00125 d_is_global_attribute = at.d_is_global_attribute; 00126 00127 // Set the parent to null (no parent, not in container) 00128 // since using at.d_parent is semantically incorrect 00129 // and potentially dangerous. 00130 d_parent = 0; 00131 00132 Attr_citer i = at.attr_map.begin(); 00133 Attr_citer ie = at.attr_map.end(); 00134 for (; i != ie; ++i) { 00135 // this deep-copies containers recursively 00136 entry *e = new entry(*(*i)); 00137 attr_map.push_back(e); 00138 00139 // If the entry being added was a container, 00140 // set its parent to this to maintain invariant. 00141 if (e->type == Attr_container) { 00142 assert(e->attributes); 00143 e->attributes->d_parent = this; 00144 } 00145 } 00146 } 00147 00151 AttrTable::AttrTable() 00152 : DapObj() 00153 , d_name("") 00154 , d_parent(0) 00155 , attr_map() 00156 , d_is_global_attribute(true) 00157 { 00158 } 00159 00160 AttrTable::AttrTable(const AttrTable &rhs) 00161 : DapObj() 00162 { 00163 clone(rhs); 00164 } 00165 00166 // Private 00167 void AttrTable::delete_attr_table() 00168 { 00169 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 00170 delete *i; 00171 *i = 0; 00172 } 00173 attr_map.clear(); 00174 } 00175 00176 AttrTable::~AttrTable() 00177 { 00178 DBG(cerr << "Entering ~AttrTable (" << this << ")" << endl); 00179 delete_attr_table();DBG(cerr << "Exiting ~AttrTable" << endl); 00180 } 00181 00182 AttrTable & 00183 AttrTable::operator=(const AttrTable &rhs) 00184 { 00185 if (this != &rhs) { 00186 delete_attr_table(); 00187 clone(rhs); 00188 } 00189 00190 return *this; 00191 } 00193 00199 unsigned int 00200 AttrTable::get_size() const 00201 { 00202 return attr_map.size(); 00203 } 00204 00207 string 00208 AttrTable::get_name() const 00209 { 00210 return d_name; 00211 } 00212 00215 void 00216 AttrTable::set_name(const string &n) 00217 { 00218 d_name = www2id(n); 00219 } 00220 00238 unsigned int 00239 AttrTable::append_attr(const string &name, const string &type, 00240 const string &attribute) 00241 { 00242 DBG(cerr << "Entering AttrTable::append_attr" << endl); 00243 string lname = www2id(name); 00244 00245 Attr_iter iter = simple_find(lname); 00246 00247 // If the types don't match OR this attribute is a container, calling 00248 // this mfunc is an error! 00249 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type))) 00250 throw Error(string("An attribute called `") + name 00251 + string("' already exists but is of a different type")); 00252 if (iter != attr_map.end() && (get_type(iter) == "Container")) 00253 throw Error(string("An attribute called `") + name 00254 + string("' already exists but is a container.")); 00255 00256 if (iter != attr_map.end()) { // Must be a new attribute value; add it. 00257 (*iter)->attr->push_back(attribute); 00258 return (*iter)->attr->size(); 00259 } 00260 else { // Must be a completely new attribute; add it 00261 entry *e = new entry; 00262 00263 e->name = lname; 00264 e->is_alias = false; 00265 e->type = String_to_AttrType(type); // Record type using standard names. 00266 e->attr = new vector<string>; 00267 e->attr->push_back(attribute); 00268 00269 attr_map.push_back(e); 00270 00271 return e->attr->size(); // return the length of the attr vector 00272 } 00273 } 00274 00293 unsigned int 00294 AttrTable::append_attr(const string &name, const string &type, 00295 vector<string> *values) 00296 { 00297 DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl); 00298 string lname = www2id(name); 00299 00300 Attr_iter iter = simple_find(lname); 00301 00302 // If the types don't match OR this attribute is a container, calling 00303 // this mfunc is an error! 00304 if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type))) 00305 throw Error(string("An attribute called `") + name 00306 + string("' already exists but is of a different type")); 00307 if (iter != attr_map.end() && (get_type(iter) == "Container")) 00308 throw Error(string("An attribute called `") + name 00309 + string("' already exists but is a container.")); 00310 00311 if (iter != attr_map.end()) { // Must be new attribute values; add. 00312 vector<string>::iterator i = values->begin(); 00313 while (i != values->end()) 00314 (*iter)->attr->push_back(*i++); 00315 00316 return (*iter)->attr->size(); 00317 } 00318 else { // Must be a completely new attribute; add it 00319 entry *e = new entry; 00320 00321 e->name = lname; 00322 e->is_alias = false; 00323 e->type = String_to_AttrType(type); // Record type using standard names. 00324 e->attr = new vector<string>(*values); 00325 00326 attr_map.push_back(e); 00327 00328 return e->attr->size(); // return the length of the attr vector 00329 } 00330 } 00331 00341 AttrTable * 00342 AttrTable::append_container(const string &name) 00343 { 00344 AttrTable *new_at = new AttrTable; 00345 AttrTable *ret = NULL; 00346 try { 00347 ret = append_container(new_at, name); 00348 } 00349 catch (Error &e) { 00350 // an error occurred, attribute with that name already exists 00351 delete new_at; new_at = 0; 00352 throw ; 00353 } 00354 return ret; 00355 } 00356 00371 AttrTable * 00372 AttrTable::append_container(AttrTable *at, const string &name) 00373 { 00374 string lname = www2id(name); 00375 00376 if (simple_find(name) != attr_end()) 00377 throw Error(string("There already exists a container called `") 00378 + name + string("' in this attribute table.")); 00379 DBG(cerr << "Setting appended attribute container name to: " 00380 << lname << endl); 00381 at->set_name(lname); 00382 00383 entry *e = new entry; 00384 e->name = lname; 00385 e->is_alias = false; 00386 e->type = Attr_container; 00387 e->attributes = at; 00388 00389 attr_map.push_back(e); 00390 00391 at->d_parent = this; 00392 00393 return e->attributes; 00394 } 00395 00410 void 00411 AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter) 00412 { 00413 string::size_type dotpos = target.rfind('.'); 00414 if (dotpos != string::npos) { 00415 string container = target.substr(0, dotpos); 00416 string field = target.substr(dotpos + 1); 00417 00418 *at = find_container(container); 00419 if (*at) { 00420 *iter = (*at)->simple_find(field); 00421 } 00422 else { 00423 *iter = attr_map.end(); 00424 } 00425 } 00426 else { 00427 *at = recurrsive_find(target, iter); 00428 } 00429 } 00430 00442 AttrTable * 00443 AttrTable::recurrsive_find(const string &target, Attr_iter *location) 00444 { 00445 //*location = attr_begin(); 00446 Attr_iter i = attr_begin(); 00447 while (i != attr_end()) { 00448 if (target == (*i)->name) { 00449 *location = i; 00450 return this; 00451 } 00452 else if ((*i)->type == Attr_container) { 00453 AttrTable *at = (*i)->attributes->recurrsive_find(target, location); 00454 if (at) 00455 return at; 00456 } 00457 00458 ++i; 00459 } 00460 00461 *location = i; 00462 return 0; 00463 } 00464 00465 // Made public for callers that want non-recursive find. [mjohnson 6 oct 09] 00472 AttrTable::Attr_iter 00473 AttrTable::simple_find(const string &target) 00474 { 00475 Attr_iter i; 00476 for (i = attr_map.begin(); i != attr_map.end(); ++i) { 00477 if (target == (*i)->name) { 00478 break; 00479 } 00480 } 00481 return i; 00482 } 00483 00497 AttrTable * 00498 AttrTable::find_container(const string &target) 00499 { 00500 string::size_type dotpos = target.find('.'); 00501 if (dotpos != string::npos) { 00502 string container = target.substr(0, dotpos); 00503 string field = target.substr(dotpos + 1); 00504 00505 AttrTable *at = simple_find_container(container); 00506 return (at) ? at->find_container(field) : 0; 00507 } 00508 else { 00509 return simple_find_container(target); 00510 } 00511 } 00512 00513 // Made public for callers that want non-recursive find. [mjohnson 6 oct 09] 00514 AttrTable * 00515 AttrTable::simple_find_container(const string &target) 00516 { 00517 if (get_name() == target) 00518 return this; 00519 00520 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 00521 if (is_container(i) && target == (*i)->name) { 00522 return (*i)->attributes; 00523 } 00524 } 00525 00526 return 0; 00527 } 00528 00536 00538 AttrTable * 00539 AttrTable::get_attr_table(const string &name) 00540 { 00541 return find_container(name); 00542 } 00543 00545 string 00546 AttrTable::get_type(const string &name) 00547 { 00548 Attr_iter p = simple_find(name); 00549 return (p != attr_map.end()) ? get_type(p) : (string)""; 00550 } 00551 00554 AttrType 00555 AttrTable::get_attr_type(const string &name) 00556 { 00557 Attr_iter p = simple_find(name); 00558 return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown; 00559 } 00560 00568 unsigned int 00569 AttrTable::get_attr_num(const string &name) 00570 { 00571 Attr_iter iter = simple_find(name); 00572 return (iter != attr_map.end()) ? get_attr_num(iter) : 0; 00573 } 00574 00587 vector<string> * 00588 AttrTable::get_attr_vector(const string &name) 00589 { 00590 Attr_iter p = simple_find(name); 00591 return (p != attr_map.end()) ? get_attr_vector(p) : 0; 00592 } 00593 00610 void 00611 AttrTable::del_attr(const string &name, int i) 00612 { 00613 string lname = www2id(name); 00614 00615 Attr_iter iter = simple_find(lname); 00616 if (iter != attr_map.end()) { 00617 if (i == -1) { // Delete the whole attribute 00618 entry *e = *iter; 00619 attr_map.erase(iter); 00620 delete e; e = 0; 00621 } 00622 else { // Delete one element from attribute array 00623 // Don't try to delete elements from the vector of values if the 00624 // map is a container! 00625 if ((*iter)->type == Attr_container) 00626 return; 00627 00628 vector<string> *sxp = (*iter)->attr; 00629 00630 assert(i >= 0 && i < (int)sxp->size()); 00631 sxp->erase(sxp->begin() + i); // rm the element 00632 } 00633 } 00634 } 00635 00637 00642 AttrTable::Attr_iter 00643 AttrTable::attr_begin() 00644 { 00645 return attr_map.begin(); 00646 } 00647 00651 AttrTable::Attr_iter 00652 AttrTable::attr_end() 00653 { 00654 return attr_map.end(); 00655 } 00656 00665 AttrTable::Attr_iter 00666 AttrTable::get_attr_iter(int i) 00667 { 00668 return attr_map.begin() + i; 00669 } 00670 00672 string 00673 AttrTable::get_name(Attr_iter iter) 00674 { 00675 assert(iter != attr_map.end()); 00676 00677 return (*iter)->name; 00678 } 00679 00681 bool 00682 AttrTable::is_container(Attr_iter i) 00683 { 00684 return (*i)->type == Attr_container; 00685 } 00686 00692 AttrTable * 00693 AttrTable::get_attr_table(Attr_iter iter) 00694 { 00695 assert(iter != attr_map.end()); 00696 return (*iter)->type == Attr_container ? (*iter)->attributes : 0; 00697 } 00698 00707 AttrTable::Attr_iter 00708 AttrTable::del_attr_table(Attr_iter iter) 00709 { 00710 if ((*iter)->type != Attr_container) 00711 return ++iter; 00712 00713 // the caller intends to delete/reuse the contained AttrTable, 00714 // so zero it out so it doesn't get deleted before we delete the entry 00715 // [mjohnson] 00716 struct entry* e = *iter; 00717 // container no longer has a parent. 00718 if (e->attributes) { 00719 e->attributes->d_parent = 0; 00720 } 00721 e->attributes = 0; 00722 delete e; 00723 00724 return attr_map.erase(iter); 00725 } 00726 00730 string 00731 AttrTable::get_type(Attr_iter iter) 00732 { 00733 assert(iter != attr_map.end()); 00734 return AttrType_to_String((*iter)->type); 00735 } 00736 00740 AttrType 00741 AttrTable::get_attr_type(Attr_iter iter) 00742 { 00743 return (*iter)->type; 00744 } 00745 00753 unsigned int 00754 AttrTable::get_attr_num(Attr_iter iter) 00755 { 00756 assert(iter != attr_map.end()); 00757 return ((*iter)->type == Attr_container) 00758 ? (*iter)->attributes->get_size() 00759 : (*iter)->attr->size(); 00760 } 00761 00778 string 00779 AttrTable::get_attr(Attr_iter iter, unsigned int i) 00780 { 00781 assert(iter != attr_map.end()); 00782 #if 1 00783 return (*iter)->type == Attr_container ? (string)"None" : (*(*iter)->attr)[i]; 00784 #else 00785 if ((*iter)->type == Attr_container) { 00786 return "None"; 00787 } 00788 else { 00789 cerr << "(*iter)->attr: " << (*iter)->attr << endl; 00790 cerr << "(*iter)->name: " << (*iter)->name << endl; 00791 cerr << "(*iter)->type: " << (*iter)->type << endl; 00792 //cerr << "get_attr: return value: [" << i << "]: " << (*(*iter)->attr)[i]<< endl; 00793 if ((*iter)->name == "SIS_ID") 00794 return "SIS_ID_value"; 00795 else 00796 return (*(*iter)->attr)[i]; 00797 } 00798 #endif 00799 } 00800 00801 string 00802 AttrTable::get_attr(const string &name, unsigned int i) 00803 { 00804 Attr_iter p = simple_find(name); 00805 return (p != attr_map.end()) ? get_attr(p, i) : (string)""; 00806 } 00807 00819 vector<string> * 00820 AttrTable::get_attr_vector(Attr_iter iter) 00821 { 00822 assert(iter != attr_map.end()); 00823 return (*iter)->type != Attr_container ? (*iter)->attr : 0; 00824 } 00825 00826 bool 00827 AttrTable::is_global_attribute(Attr_iter iter) 00828 { 00829 assert(iter != attr_map.end()); 00830 if ((*iter)->type == Attr_container) 00831 return (*iter)->attributes->is_global_attribute(); 00832 else 00833 return (*iter)->is_global; 00834 } 00835 00836 void 00837 AttrTable::set_is_global_attribute(Attr_iter iter, bool ga) 00838 { 00839 assert(iter != attr_map.end()); 00840 if ((*iter)->type == Attr_container) 00841 (*iter)->attributes->set_is_global_attribute(ga); 00842 else 00843 (*iter)->is_global = ga; 00844 } 00845 00847 00848 // Alias an attribute table. The alias should be added to this object. 00854 void 00855 AttrTable::add_container_alias(const string &name, AttrTable *src) 00856 { 00857 string lname = www2id(name); 00858 00859 if (simple_find(lname) != attr_end()) 00860 throw Error(string("There already exists a container called `") 00861 + name + string("in this attribute table.")); 00862 00863 entry *e = new entry; 00864 e->name = lname; 00865 e->is_alias = true; 00866 e->aliased_to = src->get_name(); 00867 e->type = Attr_container; 00868 00869 e->attributes = src; 00870 00871 attr_map.push_back(e); 00872 } 00873 00886 void 00887 AttrTable::add_value_alias(AttrTable *das, const string &name, 00888 const string &source) 00889 { 00890 string lname = www2id(name); 00891 string lsource = www2id(source); 00892 00893 // find the container that holds source and its (sources's) iterator 00894 // within that container. Search at the uppermost level of the attribute 00895 // object to find values defined `above' the current container. 00896 AttrTable *at; 00897 Attr_iter iter; 00898 das->find(lsource, &at, &iter); 00899 00900 // If source is not found by looking at the topmost level, look in the 00901 // current table (i.e., alias z x where x is in the current container 00902 // won't be found by looking for `x' at the top level). See test case 26 00903 // in das-testsuite. 00904 if (!at || (iter == at->attr_end()) || !*iter) { 00905 find(lsource, &at, &iter); 00906 if (!at || (iter == at->attr_end()) || !*iter) 00907 throw Error(string("Could not find the attribute `") 00908 + source + string("' in the attribute object.")); 00909 } 00910 00911 // If we've got a value to alias and it's being added at the top level of 00912 // the DAS, that's an error. 00913 if (at && !at->is_container(iter) && this == das) 00914 throw Error(string("A value cannot be aliased to the top level of the DAS;\nOnly containers may be present at that level of the DAS.")); 00915 00916 if (simple_find(lname) != attr_end()) 00917 throw Error(string("There already exists a container called `") 00918 + name + string("in this attribute table.")); 00919 00920 entry *e = new entry; 00921 e->name = lname; 00922 e->is_alias = true; 00923 e->aliased_to = lsource; 00924 e->type = get_attr_type(iter); 00925 if (at && e->type == Attr_container) 00926 e->attributes = at->get_attr_table(iter); 00927 else 00928 e->attr = (*iter)->attr; 00929 00930 attr_map.push_back(e); 00931 } 00932 00933 // Deprecated 00952 bool 00953 AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name) 00954 { 00955 add_value_alias(at, alias, name); 00956 return true; 00957 } 00958 00966 bool 00967 AttrTable::attr_alias(const string &alias, const string &name) 00968 { 00969 return attr_alias(alias, this, name); 00970 } 00971 00975 void 00976 AttrTable::erase() 00977 { 00978 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 00979 delete *i; *i = 0; 00980 } 00981 00982 attr_map.erase(attr_map.begin(), attr_map.end()); 00983 00984 d_name = ""; 00985 } 00986 00987 const string double_quote = "\""; 00988 00989 // This is here as a result of the problem described in ticket #1163 where 00990 // the data handlers are adding quotes to string attributes so the DAS will 00991 // be printed correctly. But that has the affect of adding the quotes to the 00992 // attribute's _value_ not just it's print representation. As part of the fix 00993 // I made the code here add the quotes if the handlers are fixed (but not if 00994 // handlers are still adding them). The other part of 1163 is to fix all of 00995 // the handlers... What this fix means is that attributes whose values really 00996 // do contain bracketing quotes might be misunderstood, since we're assuming 00997 // those quotes were added by the handlers as a hack to get the output 00998 // formatting correct for the DAS. jhrg 7/30/08 00999 01000 static void 01001 write_string_attribute_for_das(ostream &out, const string &value, const string &term) 01002 { 01003 if (is_quoted(value)) 01004 out << value << term; 01005 else 01006 out << double_quote << value << double_quote << term; 01007 } 01008 01009 static void 01010 write_string_attribute_for_das(FILE *out, const string &value, const string &term) 01011 { 01012 if (is_quoted(value)) 01013 fprintf(out, "%s%s", value.c_str(), term.c_str()); 01014 else 01015 fprintf(out, "\"%s\"%s", value.c_str(), term.c_str()); 01016 } 01017 01018 // Special treatment for XML: Make sure to escape double quotes when XML is 01019 // printed in a DAS. 01020 static void 01021 write_xml_attribute_for_das(ostream &out, const string &value, const string &term) 01022 { 01023 if (is_quoted(value)) 01024 out << escape_double_quotes(value) << term; 01025 else 01026 out << double_quote << escape_double_quotes(value) << double_quote << term; 01027 } 01028 01029 static void 01030 write_xml_attribute_for_das(FILE *out, const string &value, const string &term) 01031 { 01032 if (is_quoted(value)) 01033 fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str()); 01034 else 01035 fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str()); 01036 } 01037 01040 void 01041 AttrTable::simple_print(FILE *out, string pad, Attr_iter i, 01042 bool dereference) 01043 { 01044 switch ((*i)->type) { 01045 case Attr_container: 01046 fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str()); 01047 01048 (*i)->attributes->print(out, pad + " ", dereference); 01049 01050 fprintf(out, "%s}\n", pad.c_str()); 01051 break; 01052 01053 case Attr_string: { 01054 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), 01055 id2www(get_name(i)).c_str()); 01056 01057 vector<string> *sxp = (*i)->attr; 01058 vector<string>::iterator last = sxp->end() - 1; 01059 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01060 write_string_attribute_for_das(out, *i, ", "); 01061 } 01062 write_string_attribute_for_das(out, *last, ";\n"); 01063 } 01064 break; 01065 01066 case Attr_other_xml: { 01067 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), 01068 id2www(get_name(i)).c_str()); 01069 01070 vector<string> *sxp = (*i)->attr; 01071 vector<string>::iterator last = sxp->end() - 1; 01072 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01073 write_xml_attribute_for_das(out, *i, ", "); 01074 } 01075 write_xml_attribute_for_das(out, *last, ";\n"); 01076 } 01077 break; 01078 01079 default: { 01080 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), 01081 id2www(get_name(i)).c_str()); 01082 01083 vector<string> *sxp = (*i)->attr; 01084 vector<string>::iterator last = sxp->end() - 1; 01085 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01086 fprintf(out, "%s%s", (*i).c_str(), ", "); 01087 } 01088 fprintf(out, "%s%s", (*last).c_str(), ";\n"); 01089 } 01090 break; 01091 } 01092 } 01093 01096 void 01097 AttrTable::simple_print(ostream &out, string pad, Attr_iter i, 01098 bool dereference) 01099 { 01100 switch ((*i)->type) { 01101 case Attr_container: 01102 out << pad << id2www(get_name(i)) << " {\n"; 01103 01104 (*i)->attributes->print(out, pad + " ", dereference); 01105 01106 out << pad << "}\n"; 01107 break; 01108 01109 case Attr_string: { 01110 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01111 01112 vector<string> *sxp = (*i)->attr; 01113 vector<string>::iterator last = sxp->end() - 1; 01114 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01115 write_string_attribute_for_das(out, *i, ", "); 01116 } 01117 write_string_attribute_for_das(out, *last, ";\n"); 01118 } 01119 break; 01120 01121 case Attr_other_xml: { 01122 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01123 01124 vector<string> *sxp = (*i)->attr; 01125 vector<string>::iterator last = sxp->end() - 1; 01126 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01127 write_xml_attribute_for_das(out, *i, ", "); 01128 } 01129 write_xml_attribute_for_das(out, *last, ";\n"); 01130 } 01131 break; 01132 01133 default: { 01134 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01135 01136 vector<string> *sxp = (*i)->attr; 01137 vector<string>::iterator last = sxp->end() - 1; 01138 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01139 out << *i <<", "; 01140 } 01141 out << *last << ";\n"; 01142 } 01143 break; 01144 } 01145 } 01146 01157 void 01158 AttrTable::print(FILE *out, string pad, bool dereference) 01159 { 01160 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 01161 if ((*i)->is_alias) { 01162 if (dereference) { 01163 simple_print(out, pad, i, dereference); 01164 } 01165 else { 01166 fprintf(out, "%sAlias %s %s;\n", 01167 pad.c_str(), 01168 id2www(get_name(i)).c_str(), 01169 id2www((*i)->aliased_to).c_str()); 01170 } 01171 } 01172 else { 01173 simple_print(out, pad, i, dereference); 01174 } 01175 } 01176 } 01177 01188 void 01189 AttrTable::print(ostream &out, string pad, bool dereference) 01190 { 01191 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 01192 if ((*i)->is_alias) { 01193 if (dereference) { 01194 simple_print(out, pad, i, dereference); 01195 } 01196 else { 01197 out << pad << "Alias " << id2www(get_name(i)) 01198 << " " << id2www((*i)->aliased_to) << ";\n"; 01199 } 01200 } 01201 else { 01202 simple_print(out, pad, i, dereference); 01203 } 01204 } 01205 } 01206 01211 void 01212 AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/) 01213 { 01214 // Why this works: AttrTable is really a hacked class that used to 01215 // implement a single-level set of attributes. Containers 01216 // were added several years later by dropping in the 'entry' structure. 01217 // It's not a class in its own right; instead accessors from AttrTable 01218 // are used to access information from entry. So... the loop below 01219 // actually iterates over the entries of *this* (which is an instance of 01220 // AttrTable). A container is an entry whose sole value is an AttrTable 01221 // instance. 05/19/03 jhrg 01222 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) { 01223 if ((*i)->is_alias) { 01224 fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n", 01225 pad.c_str(), id2xml(get_name(i)).c_str(), 01226 (*i)->aliased_to.c_str()); 01227 01228 } 01229 else if (is_container(i)) { 01230 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n", 01231 pad.c_str(), id2xml(get_name(i)).c_str(), 01232 get_type(i).c_str()); 01233 01234 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/); 01235 01236 fprintf(out, "%s</Attribute>\n", pad.c_str()); 01237 } 01238 else { 01239 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n", 01240 pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str()); 01241 01242 string value_pad = pad + " "; 01243 // Special handling for the OtherXML attribute type - don't escape 01244 // the XML and don't include the <value> element. Note that there 01245 // cannot be an vector of XML things as can be with the other types. 01246 if (get_attr_type(i) == Attr_other_xml) { 01247 if (get_attr_num(i) != 1) 01248 throw Error("OtherXML attributes cannot be vector-valued."); 01249 fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str()); 01250 } 01251 else { 01252 for (unsigned j = 0; j < get_attr_num(i); ++j) { 01253 fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(), 01254 id2xml(get_attr(i, j)).c_str()); 01255 } 01256 } 01257 fprintf(out, "%s</Attribute>\n", pad.c_str()); 01258 } 01259 } 01260 } 01261 01266 void 01267 AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/) 01268 { 01269 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) { 01270 if ((*i)->is_alias) { 01271 out << pad << "<Alias name=\"" << id2xml(get_name(i)) 01272 << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n"; 01273 01274 } 01275 else if (is_container(i)) { 01276 out << pad << "<Attribute name=\"" << id2xml(get_name(i)) 01277 << "\" type=\"" << get_type(i) << "\">\n"; 01278 01279 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/); 01280 01281 out << pad << "</Attribute>\n"; 01282 } 01283 else { 01284 out << pad << "<Attribute name=\"" << id2xml(get_name(i)) 01285 << "\" type=\"" << get_type(i) << "\">\n"; 01286 01287 string value_pad = pad + " "; 01288 if (get_attr_type(i) == Attr_other_xml) { 01289 if (get_attr_num(i) != 1) 01290 throw Error("OtherXML attributes cannot be vector-valued."); 01291 out << value_pad << get_attr(i, 0) << "\n"; 01292 } 01293 else { 01294 string value_pad = pad + " "; 01295 for (unsigned j = 0; j < get_attr_num(i); ++j) { 01296 out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n"; 01297 } 01298 } 01299 out << pad << "</Attribute>\n"; 01300 } 01301 } 01302 } 01303 01311 void 01312 AttrTable::dump(ostream &strm) const 01313 { 01314 strm << DapIndent::LMarg << "AttrTable::dump - (" 01315 << (void *)this << ")" << endl; 01316 DapIndent::Indent(); 01317 strm << DapIndent::LMarg << "table name: " << d_name << endl; 01318 if (attr_map.size()) { 01319 strm << DapIndent::LMarg << "attributes: " << endl; 01320 DapIndent::Indent(); 01321 Attr_citer i = attr_map.begin(); 01322 Attr_citer ie = attr_map.end(); 01323 for (; i != ie; ++i) { 01324 entry *e = (*i); 01325 string type = AttrType_to_String(e->type); 01326 if (e->is_alias) { 01327 strm << DapIndent::LMarg << "alias: " << e->name 01328 << " aliased to: " << e->aliased_to 01329 << endl; 01330 } 01331 else if (e->type == Attr_container) { 01332 strm << DapIndent::LMarg << "attr: " << e->name 01333 << " of type " << type 01334 << endl; 01335 DapIndent::Indent(); 01336 e->attributes->dump(strm); 01337 DapIndent::UnIndent(); 01338 } 01339 else { 01340 strm << DapIndent::LMarg << "attr: " << e->name 01341 << " of type " << type 01342 << endl; 01343 DapIndent::Indent(); 01344 strm << DapIndent::LMarg; 01345 vector<string>::const_iterator iter = e->attr->begin(); 01346 vector<string>::const_iterator last = e->attr->end() - 1; 01347 for (; iter != last; ++iter) { 01348 strm << (*iter) << ", "; 01349 } 01350 strm << (*(e->attr->end() - 1)) << endl; 01351 DapIndent::UnIndent(); 01352 } 01353 } 01354 DapIndent::UnIndent(); 01355 } 01356 else { 01357 strm << DapIndent::LMarg << "attributes: empty" << endl; 01358 } 01359 if (d_parent) { 01360 strm << DapIndent::LMarg << "parent table:" 01361 << d_name << ":" << (void *)d_parent << endl; 01362 } 01363 else { 01364 strm << DapIndent::LMarg << "parent table: none" << d_name << endl; 01365 } 01366 DapIndent::UnIndent(); 01367 } 01368 01369 } // namespace libdap 01370