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