ximol/xml/attributes.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002  *                                                                           *
00003  * library XiMoL                                                             *
00004  * Copyright (C) 2002, 2003, 2004 Florent Tournois                           *
00005  *                                                                           *
00006  * This library is free software; you can redistribute it and/or             *
00007  * modify it under the terms of the GNU Lesser General Public                *
00008  * License as published by the Free Software Foundation; either              *
00009  * version 2.1 of the License, or (at your option) any later version.        *
00010  *                                                                           *
00011  * This library is distributed in the hope that it will be useful,           *
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00014  * Lesser General Public License for more details.                           *
00015  *                                                                           *
00016  * You should have received a copy of the GNU Lesser General Public          *
00017  * License along with this library; if not, write to the Free Software       *
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA   *
00019  *                                                                           *
00020 \*****************************************************************************/
00021 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00022 /** \file 
00023         \brief attributes implementation.
00024         
00025         \author Tournois Florent
00026         \version 1.0
00027 
00028     $Id: attributes.cpp,v 1.19 2004/02/22 10:27:34 tournois Exp $
00029     $Log: attributes.cpp,v $
00030     Revision 1.19  2004/02/22 10:27:34  tournois
00031     Add some doc.
00032 
00033     Revision 1.18  2004/02/22 09:54:21  tournois
00034     Change years on the copyright.
00035 
00036     Revision 1.17  2004/01/29 20:52:35  tournois
00037     doc and tutorial.
00038 
00039     Revision 1.16  2004/01/18 11:40:58  tournois
00040     Add the pattern facet.
00041 
00042     Revision 1.15  2003/12/10 20:32:18  tournois
00043     Fix somes bugs about attributes and now tests are all check.
00044 
00045     Revision 1.14  2003/12/09 19:57:28  tournois
00046     Fix some bugs about attributes classes.
00047 
00048     Revision 1.13  2003/12/05 13:04:41  hfp
00049     adapt supplied functions
00050 
00051     Revision 1.12  2003/12/05 10:42:53  hfp
00052     completed
00053 
00054     Revision 1.11  2003/12/04 14:44:10  hfp
00055     shortcut/uri-mapping includes default namespace
00056     ns_map swaps key with value -> faster find for main use-case
00057     throwing error in some cases
00058     interface is based on map (insert, fiind)
00059     mis-use of special values on return removed (find etc.)
00060     size() returns an size_t (unsigned)
00061 
00062     Revision 1.10  2003/12/03 12:28:46  hfp
00063     swap, copy construction and assignment
00064 
00065     Revision 1.9  2003/11/19 20:52:54  tournois
00066     Add new manipulator for stag and etag.
00067     Correct bugs and add tests.
00068 
00069     Revision 1.8  2003/11/18 18:54:52  tournois
00070     Add str_cast and drop the transformation.hpp file.
00071   */
00072 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00073 #include <ximol/xml/attributes.hpp>
00074 #include <ximol/parser/utils.hpp>
00075 #include <ximol/translation.hpp>
00076 #include <ximol/str_cast.hpp>
00077 #include <ximol/sstream.hpp>
00078 #include <ximol/error.hpp>
00079 
00080 #include <algorithm>
00081 
00082 
00083 XIMOL_BEGIN_PRIVATE_NAMESPACE
00084 ///////////////////////////////////////////////////////////////////////////////
00085 // module level stuff (private)
00086 ///////////////////////////////////////////////////////////////////////////////
00087 
00088 // helper for comparison
00089 template<class MapT>
00090 struct second_comp {
00091         second_comp(typename MapT::value_type::second_type const& second)
00092         : second_(second) {}
00093 
00094         bool operator()(typename MapT::value_type const& value) const {
00095                 return value.second == second_;
00096         }
00097 
00098         typename MapT::value_type::second_type const &second_;
00099 };
00100 
00101 ///////////////////////////////////////////////////////////////////////////////
00102 XIMOL_END_PRIVATE_NAMESPACE
00103 
00104 
00105 XIMOL_XML_BEGIN_NAMESPACE
00106 ///////////////////////////////////////////////////////////////////////////////
00107 // class attributes (private)
00108 ///////////////////////////////////////////////////////////////////////////////
00109 
00110 xstring const attributes::shortcut_default_uri_; // empty string
00111 
00112 
00113 ///////////////////////////////////////////////////////////////////////////////
00114 // constructor(s) & destructor
00115 ///////////////////////////////////////////////////////////////////////////////
00116 
00117 attributes::attributes()
00118 {
00119 }
00120 
00121 ///////////////////////////////////////////////////////////////////////////////
00122 
00123 attributes::attributes(attributes const& rhs)
00124 : map_(rhs.map_)
00125 , map_uri_(rhs.map_uri_)
00126 {
00127 }
00128 
00129 ///////////////////////////////////////////////////////////////////////////////
00130 
00131 attributes::~attributes()
00132 {
00133 }
00134 
00135 
00136 ///////////////////////////////////////////////////////////////////////////////
00137 // methods (public)
00138 ///////////////////////////////////////////////////////////////////////////////
00139 
00140 void attributes::swap(attributes& rhs) throw()
00141 {
00142         map_.swap(rhs.map_);
00143         map_uri_.swap(rhs.map_uri_);
00144 }
00145 
00146 ///////////////////////////////////////////////////////////////////////////////
00147 
00148 void attributes::clear()
00149 {
00150         map_.clear();
00151         map_uri_.clear();
00152 }
00153 
00154 ///////////////////////////////////////////////////////////////////////////////
00155 
00156 attributes& attributes::operator+=(attributes const& rhs)
00157 {
00158         for(const_iterator i = rhs.begin(), i_end = rhs.end();
00159                 i != i_end; ++i)
00160         {
00161                 insert(i->first.first, i->first.second, i->second);
00162         }
00163 
00164         for(const_ns_iterator ns_i = rhs.ns_begin(), ns_i_end = rhs.ns_end();
00165                 ns_i != ns_i_end; ++ns_i)
00166         {
00167                 insert_namespace(ns_i->second, /* short cut*/ 
00168                          ns_i->first); /* uri      */
00169         }
00170 
00171         return *this;
00172 }
00173 
00174 ///////////////////////////////////////////////////////////////////////////////
00175 
00176 attributes::const_ns_iterator 
00177 attributes::find_namespace(xstring const& short_ns) const
00178 { 
00179     return std::find_if(map_uri_.begin(), map_uri_.end(),
00180                 second_comp<map_uri_type>(short_ns)); 
00181 }
00182 
00183 attributes::const_ns_iterator // return type
00184 attributes::find_short_namespace(xstring const& uri) const
00185 {
00186         return map_uri_.find(uri);
00187 }
00188 
00189 ///////////////////////////////////////////////////////////////////////////////
00190 
00191 std::pair<attributes::ns_iterator, bool> // return type
00192 attributes::insert_namespace(xstring const& short_ns, xstring const& uri)
00193 {
00194         if ((!XIMOL_PARSER_NAMESPACE_PATH::is_ncname(short_ns))&&
00195         (shortcut_default_uri_!=short_ns))
00196                 XIMOL_THROW << _(L"There is no ncname") << XIMOL_AS_ERROR;
00197     
00198     if (find_namespace(short_ns)!=map_uri_.end())
00199     { 
00200         map_uri_.erase(find_namespace(short_ns)->first);
00201     };
00202 
00203     if (find_short_namespace(uri)!=map_uri_.end())
00204     {
00205         map_uri_.erase(find_short_namespace(uri)->first);
00206     };
00207 
00208         return map_uri_.insert(map_uri_type::value_type(uri, short_ns));
00209 }
00210 
00211 ///////////////////////////////////////////////////////////////////////////////
00212 
00213 std::pair<attributes::iterator, bool> // return type
00214 attributes::insert(xstring const& namespace_name, xstring const& name, xstring const& value)
00215 {
00216         if(!XIMOL_PARSER_NAMESPACE_PATH::is_ncname(name))
00217                 XIMOL_THROW << _(L"There is no ncname") << XIMOL_AS_ERROR;
00218 
00219     const_ns_iterator const itr_uri = find_namespace(namespace_name);
00220 
00221         qname_type qname(itr_uri != ns_end() // is namespace_name a short cut?
00222                 ? itr_uri->first        // the mapped uri
00223                 : namespace_name,       // is already an uri
00224                 name);
00225 
00226         return map_.insert(map_type::value_type(qname, value));
00227 }
00228 
00229 void attributes::set(xstring const& namespace_name, xstring const& name, xstring const& value)
00230 {
00231         insert(namespace_name,name,value).first->second = value;
00232 }
00233 
00234 ///////////////////////////////////////////////////////////////////////////////
00235 
00236 attributes::const_iterator // return type
00237 attributes::find(xstring const& namespace_name, xstring const& name) const
00238 {
00239     const_ns_iterator const itr_uri = find_namespace(namespace_name);
00240 
00241         return map_.find(qname_type(itr_uri != ns_end() // short cut?
00242                 ? itr_uri->first        // the mapped uri
00243                 : namespace_name,       // is already an uri
00244                 name));;
00245 }
00246 
00247 ///////////////////////////////////////////////////////////////////////////////
00248 
00249 xostream& attributes::write(xostream& xos) const
00250 {
00251         XIMOL_PARSER_USING_NAMESPACE;
00252 
00253     // write the attributes 
00254     xstring short_ns;
00255         for(const_iterator i = begin(), i_end = end();
00256                 i != i_end; ++i)
00257         {
00258                 write_space(xos);
00259 
00260         // try to get the short namspace in the attributes list
00261                 const_ns_iterator const i_short_ns = find_short_namespace(i->first.first);
00262 
00263         if (i_short_ns != ns_end()) {
00264             short_ns = i_short_ns->second; // the short cut define in this attributes list
00265         } else {
00266                         short_ns = xos.context.get_short_namespace(i->first.first); // the short cut define in the xos
00267         };
00268 
00269                 write_attribute(xos, i->first.second, i->second, short_ns);
00270         }
00271 
00272     // write the namespace declaration: the default namespace is also included
00273         for(const_ns_iterator ns_i = ns_begin(), ns_i_end = ns_end();
00274                 ns_i != ns_i_end; ++ns_i)
00275         {
00276                 write_space(xos);
00277                 write_ns_att_name(xos, ns_i->second);
00278                 write_eq(xos);
00279                 write_att_value(xos, ns_i->first);
00280         }
00281 
00282 
00283         return xos;
00284 }
00285 
00286 ///////////////////////////////////////////////////////////////////////////////
00287 
00288 xistream& attributes::read(xistream& xis)
00289 {
00290         clear();
00291 
00292         xchar_t xc = L'a';
00293         xstring name, short_ns, att_value;
00294         map_type att_waiting; // attributes that we need to find the ns
00295 
00296         XIMOL_PARSER_USING_NAMESPACE;
00297         read_optionnal_space(xis);
00298 
00299         static xstring const NAME_xmlns(L"xmlns");
00300 
00301     while(xis.get(xc) && is_first_char_ncname(xc)) {
00302                 xis.putback(xc);
00303                 read_attribute(xis, name, att_value, short_ns);
00304                 read_optionnal_space(xis);
00305 
00306 
00307         // test if it is a namespace declaration
00308         if (short_ns == NAME_xmlns) 
00309         {
00310                     insert_namespace(name, att_value); // std namespace
00311         } else {
00312             if (name == NAME_xmlns && short_ns.empty())
00313                 insert_namespace(L"", att_value);    // global namespace
00314             else 
00315                             att_waiting[qname_type(short_ns, name)] = att_value; // std attributes
00316         }
00317         }
00318 
00319         for(iterator i = att_waiting.begin(), i_end = att_waiting.end();
00320                 i != i_end; ++i)
00321         {
00322         // try to find the real namespace
00323                 const_ns_iterator i_uri_ns = find_namespace(i->first.first); // true in the attributes value
00324 
00325                 xstring uri;
00326                 if(i_uri_ns != ns_end() && i_uri_ns->second == i->first.first)
00327                         uri = xis.context.get_namespace(i->first.first); // try in the context
00328 
00329                 if(uri == i->first.first) {
00330                         i_uri_ns = find_namespace(); // the default attributes namespace
00331 
00332                         if(i_uri_ns != ns_end())
00333                                 uri = i_uri_ns->second;
00334                 }
00335 
00336                 if(uri.empty()) uri = xis.context.get_default_namespace();      // the default xos namespace
00337 
00338                 insert(uri, i->first.second, i->second);
00339         }
00340 
00341         if(!is_first_char_ncname(xc)) xis.putback(xc);
00342 
00343         return xis;
00344 }
00345 
00346 
00347 //-----------------------------------------------------------------------------
00348 // PutTo operator for the attributes
00349 //-----------------------------------------------------------------------------
00350 ::std::ostream& operator<<(::std::ostream& os, const attributes& x)
00351 {
00352     xostringstream xos;
00353     xos << x;
00354     return os << str< ::std::string>::cast(xos.str());
00355 }
00356 
00357 ///////////////////////////////////////////////////////////////////////////////
00358 XIMOL_XML_END_NAMESPACE


Donate to the XiMoL project SourceForge.net Logo If you have any questions about XiMoL, you could write to tournois@users.sourceforge.net.