xml.h
changeset 1 67188bd752db
child 7 f227a74db59d
equal deleted inserted replaced
-1:000000000000 0:eeaea25b06d9
       
     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