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 23473 2010-09-01 20:33:22Z mjohnson $"; 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 00340 AttrTable * 00341 AttrTable::append_container(const string &name) 00342 { 00343 AttrTable *new_at = new AttrTable; 00344 AttrTable *ret = NULL; 00345 try { 00346 ret = append_container(new_at, name); 00347 } 00348 catch (Error &e) { 00349 // an error occurred, attribute with that name already exists 00350 delete new_at; new_at = 0; 00351 throw e; 00352 } 00353 return ret; 00354 } 00355 00368 AttrTable * 00369 AttrTable::append_container(AttrTable *at, const string &name) 00370 { 00371 string lname = www2id(name); 00372 00373 if (simple_find(name) != attr_end()) 00374 throw Error(string("There already exists a container called `") 00375 + name + string("' in this attribute table.")); 00376 DBG(cerr << "Setting appended attribute container name to: " 00377 << lname << endl); 00378 at->set_name(lname); 00379 00380 entry *e = new entry; 00381 e->name = lname; 00382 e->is_alias = false; 00383 e->type = Attr_container; 00384 e->attributes = at; 00385 00386 attr_map.push_back(e); 00387 00388 at->d_parent = this; 00389 00390 return e->attributes; 00391 } 00392 00407 void 00408 AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter) 00409 { 00410 string::size_type dotpos = target.rfind('.'); 00411 if (dotpos != string::npos) { 00412 string container = target.substr(0, dotpos); 00413 string field = target.substr(dotpos + 1); 00414 00415 *at = find_container(container); 00416 if (*at) { 00417 *iter = (*at)->simple_find(field); 00418 } 00419 else { 00420 *iter = attr_map.end(); 00421 } 00422 } 00423 else { 00424 *at = recurrsive_find(target, iter); 00425 } 00426 } 00427 00439 AttrTable * 00440 AttrTable::recurrsive_find(const string &target, Attr_iter *location) 00441 { 00442 //*location = attr_begin(); 00443 Attr_iter i = attr_begin(); 00444 while (i != attr_end()) { 00445 if (target == (*i)->name) { 00446 *location = i; 00447 return this; 00448 } 00449 else if ((*i)->type == Attr_container) { 00450 AttrTable *at = (*i)->attributes->recurrsive_find(target, location); 00451 if (at) 00452 return at; 00453 } 00454 00455 ++i; 00456 } 00457 00458 *location = i; 00459 return 0; 00460 } 00461 00462 // Made public for callers that want non-recursive find. [mjohnson 6 oct 09] 00469 AttrTable::Attr_iter 00470 AttrTable::simple_find(const string &target) 00471 { 00472 Attr_iter i; 00473 for (i = attr_map.begin(); i != attr_map.end(); ++i) { 00474 if (target == (*i)->name) { 00475 break; 00476 } 00477 } 00478 return i; 00479 } 00480 00494 AttrTable * 00495 AttrTable::find_container(const string &target) 00496 { 00497 string::size_type dotpos = target.find('.'); 00498 if (dotpos != string::npos) { 00499 string container = target.substr(0, dotpos); 00500 string field = target.substr(dotpos + 1); 00501 00502 AttrTable *at = simple_find_container(container); 00503 return (at) ? at->find_container(field) : 0; 00504 } 00505 else { 00506 return simple_find_container(target); 00507 } 00508 } 00509 00510 // Made public for callers that want non-recursive find. [mjohnson 6 oct 09] 00511 AttrTable * 00512 AttrTable::simple_find_container(const string &target) 00513 { 00514 if (get_name() == target) 00515 return this; 00516 00517 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 00518 if (is_container(i) && target == (*i)->name) { 00519 return (*i)->attributes; 00520 } 00521 } 00522 00523 return 0; 00524 } 00525 00533 00535 AttrTable * 00536 AttrTable::get_attr_table(const string &name) 00537 { 00538 return find_container(name); 00539 } 00540 00542 string 00543 AttrTable::get_type(const string &name) 00544 { 00545 Attr_iter p = simple_find(name); 00546 return (p != attr_map.end()) ? get_type(p) : (string)""; 00547 } 00548 00551 AttrType 00552 AttrTable::get_attr_type(const string &name) 00553 { 00554 Attr_iter p = simple_find(name); 00555 return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown; 00556 } 00557 00565 unsigned int 00566 AttrTable::get_attr_num(const string &name) 00567 { 00568 Attr_iter iter = simple_find(name); 00569 return (iter != attr_map.end()) ? get_attr_num(iter) : 0; 00570 } 00571 00584 vector<string> * 00585 AttrTable::get_attr_vector(const string &name) 00586 { 00587 Attr_iter p = simple_find(name); 00588 return (p != attr_map.end()) ? get_attr_vector(p) : 0; 00589 } 00590 00607 void 00608 AttrTable::del_attr(const string &name, int i) 00609 { 00610 string lname = www2id(name); 00611 00612 Attr_iter iter = simple_find(lname); 00613 if (iter != attr_map.end()) { 00614 if (i == -1) { // Delete the whole attribute 00615 entry *e = *iter; 00616 attr_map.erase(iter); 00617 delete e; e = 0; 00618 } 00619 else { // Delete one element from attribute array 00620 // Don't try to delete elements from the vector of values if the 00621 // map is a container! 00622 if ((*iter)->type == Attr_container) 00623 return; 00624 00625 vector<string> *sxp = (*iter)->attr; 00626 00627 assert(i >= 0 && i < (int)sxp->size()); 00628 sxp->erase(sxp->begin() + i); // rm the element 00629 } 00630 } 00631 } 00632 00634 00639 AttrTable::Attr_iter 00640 AttrTable::attr_begin() 00641 { 00642 return attr_map.begin(); 00643 } 00644 00648 AttrTable::Attr_iter 00649 AttrTable::attr_end() 00650 { 00651 return attr_map.end(); 00652 } 00653 00662 AttrTable::Attr_iter 00663 AttrTable::get_attr_iter(int i) 00664 { 00665 return attr_map.begin() + i; 00666 } 00667 00669 string 00670 AttrTable::get_name(Attr_iter iter) 00671 { 00672 assert(iter != attr_map.end()); 00673 00674 return (*iter)->name; 00675 } 00676 00678 bool 00679 AttrTable::is_container(Attr_iter i) 00680 { 00681 return (*i)->type == Attr_container; 00682 } 00683 00689 AttrTable * 00690 AttrTable::get_attr_table(Attr_iter iter) 00691 { 00692 assert(iter != attr_map.end()); 00693 return (*iter)->type == Attr_container ? (*iter)->attributes : 0; 00694 } 00695 00704 AttrTable::Attr_iter 00705 AttrTable::del_attr_table(Attr_iter iter) 00706 { 00707 if ((*iter)->type != Attr_container) 00708 return ++iter; 00709 00710 // the caller intends to delete/reuse the contained AttrTable, 00711 // so zero it out so it doesn't get deleted before we delete the entry 00712 // [mjohnson] 00713 struct entry* e = *iter; 00714 // container no longer has a parent. 00715 if (e->attributes) { 00716 e->attributes->d_parent = 0; 00717 } 00718 e->attributes = 0; 00719 delete e; 00720 00721 return attr_map.erase(iter); 00722 } 00723 00727 string 00728 AttrTable::get_type(Attr_iter iter) 00729 { 00730 assert(iter != attr_map.end()); 00731 return AttrType_to_String((*iter)->type); 00732 } 00733 00737 AttrType 00738 AttrTable::get_attr_type(Attr_iter iter) 00739 { 00740 return (*iter)->type; 00741 } 00742 00750 unsigned int 00751 AttrTable::get_attr_num(Attr_iter iter) 00752 { 00753 assert(iter != attr_map.end()); 00754 return ((*iter)->type == Attr_container) 00755 ? (*iter)->attributes->get_size() 00756 : (*iter)->attr->size(); 00757 } 00758 00775 string 00776 AttrTable::get_attr(Attr_iter iter, unsigned int i) 00777 { 00778 assert(iter != attr_map.end()); 00779 #if 1 00780 return (*iter)->type == Attr_container ? (string)"None" : (*(*iter)->attr)[i]; 00781 #else 00782 if ((*iter)->type == Attr_container) { 00783 return "None"; 00784 } 00785 else { 00786 cerr << "(*iter)->attr: " << (*iter)->attr << endl; 00787 cerr << "(*iter)->name: " << (*iter)->name << endl; 00788 cerr << "(*iter)->type: " << (*iter)->type << endl; 00789 //cerr << "get_attr: return value: [" << i << "]: " << (*(*iter)->attr)[i]<< endl; 00790 if ((*iter)->name == "SIS_ID") 00791 return "SIS_ID_value"; 00792 else 00793 return (*(*iter)->attr)[i]; 00794 } 00795 #endif 00796 } 00797 00798 string 00799 AttrTable::get_attr(const string &name, unsigned int i) 00800 { 00801 Attr_iter p = simple_find(name); 00802 return (p != attr_map.end()) ? get_attr(p, i) : (string)""; 00803 } 00804 00816 vector<string> * 00817 AttrTable::get_attr_vector(Attr_iter iter) 00818 { 00819 assert(iter != attr_map.end()); 00820 return (*iter)->type != Attr_container ? (*iter)->attr : 0; 00821 } 00822 00823 bool 00824 AttrTable::is_global_attribute(Attr_iter iter) 00825 { 00826 assert(iter != attr_map.end()); 00827 if ((*iter)->type == Attr_container) 00828 return (*iter)->attributes->is_global_attribute(); 00829 else 00830 return (*iter)->is_global; 00831 } 00832 00833 void 00834 AttrTable::set_is_global_attribute(Attr_iter iter, bool ga) 00835 { 00836 assert(iter != attr_map.end()); 00837 if ((*iter)->type == Attr_container) 00838 (*iter)->attributes->set_is_global_attribute(ga); 00839 else 00840 (*iter)->is_global = ga; 00841 } 00842 00844 00845 // Alias an attribute table. The alias should be added to this object. 00851 void 00852 AttrTable::add_container_alias(const string &name, AttrTable *src) 00853 { 00854 string lname = www2id(name); 00855 00856 if (simple_find(lname) != attr_end()) 00857 throw Error(string("There already exists a container called `") 00858 + name + string("in this attribute table.")); 00859 00860 entry *e = new entry; 00861 e->name = lname; 00862 e->is_alias = true; 00863 e->aliased_to = src->get_name(); 00864 e->type = Attr_container; 00865 00866 e->attributes = src; 00867 00868 attr_map.push_back(e); 00869 } 00870 00883 void 00884 AttrTable::add_value_alias(AttrTable *das, const string &name, 00885 const string &source) 00886 { 00887 string lname = www2id(name); 00888 string lsource = www2id(source); 00889 00890 // find the container that holds source and its (sources's) iterator 00891 // within that container. Search at the uppermost level of the attribute 00892 // object to find values defined `above' the current container. 00893 AttrTable *at; 00894 Attr_iter iter; 00895 das->find(lsource, &at, &iter); 00896 00897 // If source is not found by looking at the topmost level, look in the 00898 // current table (i.e., alias z x where x is in the current container 00899 // won't be found by looking for `x' at the top level). See test case 26 00900 // in das-testsuite. 00901 if (!at || (iter == at->attr_end()) || !*iter) { 00902 find(lsource, &at, &iter); 00903 if (!at || (iter == at->attr_end()) || !*iter) 00904 throw Error(string("Could not find the attribute `") 00905 + source + string("' in the attribute object.")); 00906 } 00907 00908 // If we've got a value to alias and it's being added at the top level of 00909 // the DAS, that's an error. 00910 if (at && !at->is_container(iter) && this == das) 00911 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.")); 00912 00913 if (simple_find(lname) != attr_end()) 00914 throw Error(string("There already exists a container called `") 00915 + name + string("in this attribute table.")); 00916 00917 entry *e = new entry; 00918 e->name = lname; 00919 e->is_alias = true; 00920 e->aliased_to = lsource; 00921 e->type = get_attr_type(iter); 00922 if (at && e->type == Attr_container) 00923 e->attributes = at->get_attr_table(iter); 00924 else 00925 e->attr = (*iter)->attr; 00926 00927 attr_map.push_back(e); 00928 } 00929 00930 // Deprecated 00949 bool 00950 AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name) 00951 { 00952 add_value_alias(at, alias, name); 00953 return true; 00954 } 00955 00963 bool 00964 AttrTable::attr_alias(const string &alias, const string &name) 00965 { 00966 return attr_alias(alias, this, name); 00967 } 00968 00972 void 00973 AttrTable::erase() 00974 { 00975 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 00976 delete *i; *i = 0; 00977 } 00978 00979 attr_map.erase(attr_map.begin(), attr_map.end()); 00980 00981 d_name = ""; 00982 } 00983 00984 const string double_quote = "\""; 00985 00986 // This is here as a result of the problem described in ticket #1163 where 00987 // the data handlers are adding quotes to string attributes so the DAS will 00988 // be printed correctly. But that has the affect of adding the quotes to the 00989 // attribute's _value_ not just it's print representation. As part of the fix 00990 // I made the code here add the quotes if the handlers are fixed (but not if 00991 // handlers are still adding them). The other part of 1163 is to fix all of 00992 // the handlers... What this fix means is that attributes whose values really 00993 // do contain bracketing quotes might be misunderstood, since we're assuming 00994 // those quotes were added by the handlers as a hack to get the output 00995 // formatting correct for the DAS. jhrg 7/30/08 00996 00997 static void 00998 write_string_attribute_for_das(ostream &out, const string &value, const string &term) 00999 { 01000 if (is_quoted(value)) 01001 out << value << term; 01002 else 01003 out << double_quote << value << double_quote << term; 01004 } 01005 01006 static void 01007 write_string_attribute_for_das(FILE *out, const string &value, const string &term) 01008 { 01009 if (is_quoted(value)) 01010 fprintf(out, "%s%s", value.c_str(), term.c_str()); 01011 else 01012 fprintf(out, "\"%s\"%s", value.c_str(), term.c_str()); 01013 } 01014 01015 // Special treatment for XML: Make sure to escape double quotes when XML is 01016 // printed in a DAS. 01017 static void 01018 write_xml_attribute_for_das(ostream &out, const string &value, const string &term) 01019 { 01020 if (is_quoted(value)) 01021 out << escape_double_quotes(value) << term; 01022 else 01023 out << double_quote << escape_double_quotes(value) << double_quote << term; 01024 } 01025 01026 static void 01027 write_xml_attribute_for_das(FILE *out, const string &value, const string &term) 01028 { 01029 if (is_quoted(value)) 01030 fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str()); 01031 else 01032 fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str()); 01033 } 01034 01037 void 01038 AttrTable::simple_print(FILE *out, string pad, Attr_iter i, 01039 bool dereference) 01040 { 01041 switch ((*i)->type) { 01042 case Attr_container: 01043 fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str()); 01044 01045 (*i)->attributes->print(out, pad + " ", dereference); 01046 01047 fprintf(out, "%s}\n", pad.c_str()); 01048 break; 01049 01050 case Attr_string: { 01051 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), 01052 id2www(get_name(i)).c_str()); 01053 01054 vector<string> *sxp = (*i)->attr; 01055 vector<string>::iterator last = sxp->end() - 1; 01056 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01057 write_string_attribute_for_das(out, *i, ", "); 01058 } 01059 write_string_attribute_for_das(out, *last, ";\n"); 01060 } 01061 break; 01062 01063 case Attr_other_xml: { 01064 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), 01065 id2www(get_name(i)).c_str()); 01066 01067 vector<string> *sxp = (*i)->attr; 01068 vector<string>::iterator last = sxp->end() - 1; 01069 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01070 write_xml_attribute_for_das(out, *i, ", "); 01071 } 01072 write_xml_attribute_for_das(out, *last, ";\n"); 01073 } 01074 break; 01075 01076 default: { 01077 fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(), 01078 id2www(get_name(i)).c_str()); 01079 01080 vector<string> *sxp = (*i)->attr; 01081 vector<string>::iterator last = sxp->end() - 1; 01082 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01083 fprintf(out, "%s%s", (*i).c_str(), ", "); 01084 } 01085 fprintf(out, "%s%s", (*last).c_str(), ";\n"); 01086 } 01087 break; 01088 } 01089 } 01090 01093 void 01094 AttrTable::simple_print(ostream &out, string pad, Attr_iter i, 01095 bool dereference) 01096 { 01097 switch ((*i)->type) { 01098 case Attr_container: 01099 out << pad << id2www(get_name(i)) << " {\n"; 01100 01101 (*i)->attributes->print(out, pad + " ", dereference); 01102 01103 out << pad << "}\n"; 01104 break; 01105 01106 case Attr_string: { 01107 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01108 01109 vector<string> *sxp = (*i)->attr; 01110 vector<string>::iterator last = sxp->end() - 1; 01111 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01112 write_string_attribute_for_das(out, *i, ", "); 01113 } 01114 write_string_attribute_for_das(out, *last, ";\n"); 01115 } 01116 break; 01117 01118 case Attr_other_xml: { 01119 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01120 01121 vector<string> *sxp = (*i)->attr; 01122 vector<string>::iterator last = sxp->end() - 1; 01123 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01124 write_xml_attribute_for_das(out, *i, ", "); 01125 } 01126 write_xml_attribute_for_das(out, *last, ";\n"); 01127 } 01128 break; 01129 01130 default: { 01131 out << pad << get_type(i) << " " << id2www(get_name(i)) << " "; 01132 01133 vector<string> *sxp = (*i)->attr; 01134 vector<string>::iterator last = sxp->end() - 1; 01135 for (vector<string>::iterator i = sxp->begin(); i != last; ++i) { 01136 out << *i <<", "; 01137 } 01138 out << *last << ";\n"; 01139 } 01140 break; 01141 } 01142 } 01143 01154 void 01155 AttrTable::print(FILE *out, string pad, bool dereference) 01156 { 01157 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 01158 if ((*i)->is_alias) { 01159 if (dereference) { 01160 simple_print(out, pad, i, dereference); 01161 } 01162 else { 01163 fprintf(out, "%sAlias %s %s;\n", 01164 pad.c_str(), 01165 id2www(get_name(i)).c_str(), 01166 id2www((*i)->aliased_to).c_str()); 01167 } 01168 } 01169 else { 01170 simple_print(out, pad, i, dereference); 01171 } 01172 } 01173 } 01174 01185 void 01186 AttrTable::print(ostream &out, string pad, bool dereference) 01187 { 01188 for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) { 01189 if ((*i)->is_alias) { 01190 if (dereference) { 01191 simple_print(out, pad, i, dereference); 01192 } 01193 else { 01194 out << pad << "Alias " << id2www(get_name(i)) 01195 << " " << id2www((*i)->aliased_to) << ";\n"; 01196 } 01197 } 01198 else { 01199 simple_print(out, pad, i, dereference); 01200 } 01201 } 01202 } 01203 01208 void 01209 AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/) 01210 { 01211 // Why this works: AttrTable is really a hacked class that used to 01212 // implement a single-level set of attributes. Containers 01213 // were added several years later by dropping in the 'entry' structure. 01214 // It's not a class in its own right; instead accessors from AttrTable 01215 // are used to access information from entry. So... the loop below 01216 // actually iterates over the entries of *this* (which is an instance of 01217 // AttrTable). A container is an entry whose sole value is an AttrTable 01218 // instance. 05/19/03 jhrg 01219 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) { 01220 if ((*i)->is_alias) { 01221 fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n", 01222 pad.c_str(), id2xml(get_name(i)).c_str(), 01223 (*i)->aliased_to.c_str()); 01224 01225 } 01226 else if (is_container(i)) { 01227 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n", 01228 pad.c_str(), id2xml(get_name(i)).c_str(), 01229 get_type(i).c_str()); 01230 01231 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/); 01232 01233 fprintf(out, "%s</Attribute>\n", pad.c_str()); 01234 } 01235 else { 01236 fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n", 01237 pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str()); 01238 01239 string value_pad = pad + " "; 01240 // Special handling for the OtherXML attribute type - don't escape 01241 // the XML and don't include the <value> element. Note that there 01242 // cannot be an vector of XML things as can be with the other types. 01243 if (get_attr_type(i) == Attr_other_xml) { 01244 if (get_attr_num(i) != 1) 01245 throw Error("OtherXML attributes cannot be vector-valued."); 01246 fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str()); 01247 } 01248 else { 01249 for (unsigned j = 0; j < get_attr_num(i); ++j) { 01250 fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(), 01251 id2xml(get_attr(i, j)).c_str()); 01252 } 01253 } 01254 fprintf(out, "%s</Attribute>\n", pad.c_str()); 01255 } 01256 } 01257 } 01258 01263 void 01264 AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/) 01265 { 01266 for (Attr_iter i = attr_begin(); i != attr_end(); ++i) { 01267 if ((*i)->is_alias) { 01268 out << pad << "<Alias name=\"" << id2xml(get_name(i)) 01269 << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n"; 01270 01271 } 01272 else if (is_container(i)) { 01273 out << pad << "<Attribute name=\"" << id2xml(get_name(i)) 01274 << "\" type=\"" << get_type(i) << "\">\n"; 01275 01276 get_attr_table(i)->print_xml(out, pad + " "/*, constrained*/); 01277 01278 out << pad << "</Attribute>\n"; 01279 } 01280 else { 01281 out << pad << "<Attribute name=\"" << id2xml(get_name(i)) 01282 << "\" type=\"" << get_type(i) << "\">\n"; 01283 01284 string value_pad = pad + " "; 01285 if (get_attr_type(i) == Attr_other_xml) { 01286 if (get_attr_num(i) != 1) 01287 throw Error("OtherXML attributes cannot be vector-valued."); 01288 out << value_pad << get_attr(i, 0) << "\n"; 01289 } 01290 else { 01291 string value_pad = pad + " "; 01292 for (unsigned j = 0; j < get_attr_num(i); ++j) { 01293 out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n"; 01294 } 01295 } 01296 out << pad << "</Attribute>\n"; 01297 } 01298 } 01299 } 01300 01308 void 01309 AttrTable::dump(ostream &strm) const 01310 { 01311 strm << DapIndent::LMarg << "AttrTable::dump - (" 01312 << (void *)this << ")" << endl; 01313 DapIndent::Indent(); 01314 strm << DapIndent::LMarg << "table name: " << d_name << endl; 01315 if (attr_map.size()) { 01316 strm << DapIndent::LMarg << "attributes: " << endl; 01317 DapIndent::Indent(); 01318 Attr_citer i = attr_map.begin(); 01319 Attr_citer ie = attr_map.end(); 01320 for (; i != ie; ++i) { 01321 entry *e = (*i); 01322 string type = AttrType_to_String(e->type); 01323 if (e->is_alias) { 01324 strm << DapIndent::LMarg << "alias: " << e->name 01325 << " aliased to: " << e->aliased_to 01326 << endl; 01327 } 01328 else if (e->type == Attr_container) { 01329 strm << DapIndent::LMarg << "attr: " << e->name 01330 << " of type " << type 01331 << endl; 01332 DapIndent::Indent(); 01333 e->attributes->dump(strm); 01334 DapIndent::UnIndent(); 01335 } 01336 else { 01337 strm << DapIndent::LMarg << "attr: " << e->name 01338 << " of type " << type 01339 << endl; 01340 DapIndent::Indent(); 01341 strm << DapIndent::LMarg; 01342 vector<string>::const_iterator iter = e->attr->begin(); 01343 vector<string>::const_iterator last = e->attr->end() - 1; 01344 for (; iter != last; iter++) { 01345 strm << (*iter) << ", "; 01346 } 01347 strm << (*(e->attr->end() - 1)) << endl; 01348 DapIndent::UnIndent(); 01349 } 01350 } 01351 DapIndent::UnIndent(); 01352 } 01353 else { 01354 strm << DapIndent::LMarg << "attributes: empty" << endl; 01355 } 01356 if (d_parent) { 01357 strm << DapIndent::LMarg << "parent table:" 01358 << d_name << ":" << (void *)d_parent << endl; 01359 } 01360 else { 01361 strm << DapIndent::LMarg << "parent table: none" << d_name << endl; 01362 } 01363 DapIndent::UnIndent(); 01364 } 01365 01366 } // namespace libdap 01367