gui/xml.h
author alpar
Wed, 16 Nov 2005 13:15:33 +0000
changeset 1803 ee8dd6872645
parent 1588 b79bcba43661
child 1875 98698b69a902
permissions -rw-r--r--
Better doc.
     1 /* -*- C++ -*-
     2  * gui/xml.h - Part of LEMON, a generic C++ optimization library
     3  *
     4  * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     5  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     6  *
     7  * Permission to use, modify and distribute this software is granted
     8  * provided that this copyright notice appears in all copies. For
     9  * precise terms see the accompanying LICENSE file.
    10  *
    11  * This software is provided "AS IS" with no warranty of any kind,
    12  * express or implied, and with no claim as to its suitability for any
    13  * purpose.
    14  *
    15  */
    16 
    17 #include <iostream>
    18 #include <string>
    19 #include <vector>
    20 #include <list>
    21 #include <map>
    22 #include <lemon/error.h>
    23 #include <lemon/xy.h>
    24 
    25 namespace lemon {
    26 
    27   class XmlIo 
    28   {
    29     bool _writeMode;
    30   public:
    31     ///Check if XmlIo is in write mode.
    32     bool write() { return _writeMode;}
    33     ///Check if XmlIo is in read mode.
    34     bool read() { return !_writeMode;}
    35 
    36     std::ostream& os;
    37     int level;
    38     
    39   protected:
    40     void indent(int level) {
    41       os << std::endl;
    42       for(int i=0;i<level;i++) os << ' ';
    43     }
    44     void tag(const std::string &_tag) {
    45       os << '<' << _tag << '>';
    46     }
    47     void etag(const std::string &_tag) {
    48       os << "</" << _tag << '>';
    49     }
    50     void itag(const std::string &_tag) { indent();tag(_tag); }
    51     void ietag(const std::string &_tag) { indent();etag(_tag); }
    52 
    53     void beginTag(const std::string &_tag) {
    54       itag(_tag);
    55       level++;
    56     }
    57     void endTag(const std::string &_tag) {
    58       level--;
    59       ietag(_tag);
    60     }
    61 
    62   public:
    63     ///Indent the line according to its level.
    64 
    65     ///\warning It can only be used in write mode.
    66     ///
    67     void indent()
    68     {
    69       if(write())
    70 	if(level>=0) indent(level);
    71 	else level=0;
    72       else throw LogicError();	
    73     }
    74   
    75     ///Read/write a tag
    76   
    77     ///Read/write a tag.
    78     ///In write mode it does not start a new line.
    79     class ContTag
    80     {
    81       XmlIo &ix;
    82       const std::string _tag;
    83     public:
    84       ///\e
    85   
    86       ///\e
    87       ///
    88       ContTag(XmlIo &_ix,const std::string &_t) :
    89 	ix(_ix), _tag(_t)
    90       {
    91 	if(ix.write()) ix.tag(_tag);
    92 	else ix.useTag(_tag);
    93       }
    94       ~ContTag() { 
    95 	if(ix.write()) ix.etag(_tag);
    96 	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);      
    97       }
    98     };
    99 
   100     ///Read/write a tag
   101   
   102     ///Read/write a tag.
   103     ///The whole <foo> ... </foo> will be places in a single line.
   104     class LineTag
   105     {
   106       XmlIo &ix;
   107       const std::string _tag;
   108     public:
   109       ///\e
   110     
   111       ///\e
   112       ///
   113       LineTag(XmlIo &_ix,const std::string &_t) :
   114 	ix(_ix), _tag(_t)
   115       {
   116 	if(ix.write()) ix.itag(_tag);
   117 	else ix.useTag(_tag);
   118       }
   119       ~LineTag() { 
   120 	if(ix.write()) ix.etag(_tag);
   121 	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
   122       }
   123     };
   124 
   125     ///Read/write a tag
   126   
   127     ///Read/write a tag.
   128     ///
   129     class Tag
   130     {
   131       XmlIo &ix;
   132       const std::string _tag;
   133     public:
   134       ///\e
   135   
   136       ///\e
   137       ///
   138       Tag(XmlIo &_ix,const std::string &_t) :
   139 	ix(_ix), _tag(_t)
   140       {
   141 	if(ix.write()) ix.beginTag(_tag);
   142 	else ix.useTag(_tag);
   143       }
   144       ~Tag() {
   145 	if(ix.write()) ix.endTag(_tag);
   146 	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
   147       }
   148     };
   149 
   150   private:
   151     std::istream& is;
   152     std::string next_tag;
   153     int line_number;
   154 
   155     void skipWhiteSpaces()
   156     {
   157       if(write()) throw LogicError();
   158       {
   159 	char c;
   160 	while (is.get(c) && std::isspace(c,is.getloc()))
   161 	  if(c=='\n') line_number++;
   162 	is.unget();
   163       }
   164     }
   165   protected:
   166     /// Use the next tag.
   167 
   168     ///\e
   169     ///
   170     void useTag() {next_tag.clear();}
   171   
   172     ///Use the next tag and check if it is equal with \c _tag
   173   
   174     ///\e
   175     ///
   176     void useTag(const std::string &_tag) {
   177       if(nextTag()==_tag) useTag();
   178       else throw DataFormatError("",line_number,"Unexpected token name");
   179     }
   180   public:
   181     ///Return the next tag (if a tag follows on the stream).
   182   
   183     ///\warning It can only be used in read mode.
   184     ///
   185     const std::string &nextTag() 
   186     {
   187       if(write()) throw LogicError();
   188       else if(next_tag.empty()) {
   189 	char c;
   190 	skipWhiteSpaces();
   191 	if(!is.get(c) || c!='<')
   192 	  throw DataFormatError("",line_number,"Bad format");
   193 	next_tag.clear();
   194 	while (is.get(c) && c!='>') next_tag.push_back(c);
   195 	if(c!='>')
   196 	  throw DataFormatError("",line_number,"Bad format");
   197       }
   198       return next_tag;
   199     }
   200 
   201     /**********************************************************************/
   202 
   203 
   204     ///\e
   205   
   206     ///\e
   207     ///
   208     XmlIo(std::ostream& _os) : _writeMode(true), os(_os),
   209 			       level(-1),
   210 			       is(*(std::istream*)(NULL)) {}
   211     ///\e
   212     ///
   213     XmlIo(std::istream& _is) : _writeMode(false),
   214 			       os(*(std::ostream*)(NULL)), is(_is),
   215 			       line_number(1) {}
   216 
   217     ~XmlIo() { if(write()) os<< std::endl; }
   218   
   219 
   220 
   221     XmlIo &operator()(const int &v) 
   222     { 
   223       if(write()) os << v;
   224       else {
   225 	skipWhiteSpaces();
   226 	if(!(is >> const_cast<int &>(v))) 
   227 	  throw DataFormatError("",line_number,"Not an 'int'");
   228       }
   229       return *this;
   230     }
   231     XmlIo &operator()(const double &v) 
   232     {
   233       if(write()) os << v;
   234       else {
   235 	skipWhiteSpaces();
   236 	if(!(is >> const_cast<double &>(v))) 
   237 	  throw DataFormatError("",line_number,"Not an 'double'");
   238       }
   239       return *this;
   240     }
   241     XmlIo &operator()(const std::string &v)
   242     {
   243       if(write())
   244 	for(std::string::const_iterator i=v.begin();i!=v.end();++i)
   245 	  switch(*i) {
   246 	  case '\\':
   247 	    os << "\\\\";
   248 	    break;
   249 	  case '<':
   250 	    os << "\\<";
   251 	    break;
   252 	  case '&':
   253 	    os << "\\&";
   254 	    break;
   255 	  case '\n':
   256 	    os << "\\n";
   257 	    break;
   258 	  default:
   259 	    os<<*i;
   260 	    break;
   261 	  }
   262       else {
   263 	std::string &w = const_cast<std::string &>(v);
   264 	w.clear();
   265 	char c;
   266 	while (is.get(c) && c!='<')
   267 	  if(c=='\\')
   268 	    if(!is.get(c))
   269 	      throw DataFormatError("",line_number,"Bad string");
   270 	    else switch(c) {
   271 	    case 'n':
   272 	      w.push_back('\n');
   273 	      break;
   274 	    default:
   275 	      w.push_back(c);
   276 	      break;
   277 	    }
   278 	  else {
   279 	    if(c=='\n') line_number++;
   280 	    w.push_back(c);
   281 	  }
   282 	if(c!='<')
   283 	  throw DataFormatError("",line_number,"Unexpected eof");
   284 	is.unget();
   285       }
   286       return *this;
   287     }
   288 
   289 
   290     XmlIo &operator()(const std::string &_tag,const int &v) 
   291     { 
   292       LineTag t(*this,_tag);
   293       (*this)(v);
   294       return *this;
   295     }
   296     XmlIo &operator()(const std::string &_tag,const double &v) 
   297     {
   298       LineTag t(*this,_tag);
   299       (*this)(v);
   300       return *this;
   301     }
   302     XmlIo &operator()(const std::string &_tag,const std::string &v)
   303     {
   304       LineTag t(*this,_tag);
   305       (*this)(v);
   306       return *this;
   307     }
   308     ///\e
   309   
   310     ///\e
   311     ///
   312     template<class V>
   313     XmlIo &operator()(const std::string &_tag,const V &v)
   314     {
   315       Tag t(*this,_tag);
   316       xml(*this,const_cast<V &>(v));
   317       return *this;
   318     }
   319     ///\e
   320   
   321     ///\e
   322     ///
   323     template<class V>
   324     XmlIo &operator()(const V &v)
   325     {
   326       xml(*this,const_cast<V &>(v));
   327       return *this;
   328     }
   329     };
   330 
   331   //////////////////////////////////////////////////////////////////////
   332   //////////////////////////////////////////////////////////////////////
   333 
   334   ///\e
   335   
   336   ///\relates XmlIo
   337   ///
   338   template<class A>
   339   void xml(XmlIo &x,std::auto_ptr<A> &v)
   340   {
   341     if(x.write()) v=new A;
   342     x(*v);
   343   }
   344   
   345   ///\e
   346   
   347   ///\relates XmlIo
   348   ///
   349   template<class A,class B>
   350   void xml(XmlIo &x,std::pair<A,B> &v)
   351   {
   352     x("first",v.first);
   353     x("second",v.second);
   354   }
   355 
   356   ///\e
   357   
   358   ///\relates XmlIo
   359   ///
   360   template<class T>
   361   void xml(XmlIo &x,std::list<T> &v)
   362   {
   363     if(x.write())
   364       for(typename std::list<T>::const_iterator it=v.begin();
   365 	  it!=v.end();++it) x("item",*it);
   366     else while(x.nextTag()=="item")
   367       {
   368 	v.push_back(T());
   369 	x("item",v.back());
   370       }
   371   }
   372   ///\e
   373   
   374   ///\relates XmlIo
   375   ///
   376   template<class T>
   377   void xml(XmlIo &x,std::vector<T> &v)
   378   {
   379     if(x.write())
   380       for(typename std::vector<T>::const_iterator it=v.begin();
   381 	  it!=v.end();++it) x("item",*it);
   382     else while(x.nextTag()=="item")
   383       {
   384 	v.push_back(T());
   385 	x("item",v.back());      
   386       }
   387   }
   388 
   389   ///\e
   390   
   391   ///\relates XmlIo
   392   ///
   393   template<class K,class V>
   394   void xml(XmlIo &x,std::map<K,V> &v)
   395   {
   396     if(x.write()) 
   397       for(typename std::map<K,V>::const_iterator it=v.begin();
   398 	  it!=v.end();++it) x("item",*it);
   399     else while(x.nextTag()=="item")
   400       {
   401 	typename std::map<K,V>::value_type it;
   402 	x("item",it);
   403 	v.insert(it);
   404       }
   405   }
   406 
   407   ///\e
   408   
   409   ///\relates XmlIo
   410   ///
   411   template<class T>
   412   void xml(XmlIo &x,lemon::xy<T> &v)
   413   {
   414     { XmlIo::LineTag t(x,"x"); x(v.x); }
   415     { XmlIo::ContTag t(x,"y"); x(v.y); }
   416   }
   417 
   418   ///\e
   419   
   420   ///\relates XmlIo
   421   ///
   422   template<class T>
   423   void xml(XmlIo &x,lemon::BoundingBox<T> &v)
   424   {
   425     if(x.write()) {
   426       if(!v.empty()) {
   427 	x("point",v.bottomLeft());
   428 	if(v.bottomLeft()!=v.topRight()) x("point",v.topRight());
   429       }
   430     }
   431     else {
   432       v.clear();
   433       while(x.nextTag()=="point") {
   434 	lemon::xy<T> co;
   435 	x("point",co);
   436 	v.add(co);
   437       }
   438     }
   439   }
   440   
   441 }
   442