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