libdap++ Updated for version 3.8.2

AttrTable.cc

Go to the documentation of this file.
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