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